10 Şubat 2021 Çarşamba

Rails İle Şirketimizin Faturalarını Takip Edelim

 Merhaba , pandemide uzun zamandır yazmadım. Ama boş durmadım. Uzun zamandır küçük işyerim için faturaları kayıt altına alabileceğim bir uygulama arıyorum. İnternette birkaç hazır site de kullandım ama hiç biri bana uymuyor ben hep onlara uymak zorunda kalıyorum. Ben kendi uygulamamı yaparım dedim. Başladım dönmeye. Önce kodsuz uygulama platformları denedim, AppGyver, Buble, FireBase, AirTable vs. baktım hepsi beni kısıtlıyor bir türlü istediğim gibi olmuyor. Döndüm yine eski ve her zaman dostum RubyOnRails'e. Debelene debelene ortaya bir uygulama çıkardım. Bu yazımda uygulamayı nasıl oluşturduğumu sizinle paylaşacağım. 

Önce veri tabanı tasarımından başlamak lazım. En korktuğum yer burası, eğer veri tabanını yanlış tasarlarsak sonra bir sürü yanlış yollarda boğulabiliriz. Şöyle bir veritabanı tasarladım.


Önce firmalar tablosu geliyor, arkasından firmalarda çalışan insanların bilgilerinin kaydedildiği bir tablo ve projelerin kaydedildiği bir tablo var. Projelere bağlı çalışanları ilişkilendireceğimiz bir bağlantı referans tablosu var. Projeler için yaptığımız harcamalar ve müşteriye kesilen faturaları kaydedeceğimiz iki adet birbirine çok benzer tablomuz var. Fatura satırları içeren ve içerdiği bilgilere ait bağlantılı tablolar da resmi bitiriyor. Sonradan bu faturalara ait ödemeler için de bir tablo ekledim yeri geldiğinde onu da açıklarım.


Projeye Başlayalım

Çalışmak istediğimiz klasörde bir konsol açıp, yeni proje üretme komutunu girelim,

rails new TakipApp

Ben Windows'ta yaparken bundle komutu https adres ile çalışmıyor, uğraşmadan gemfile içindeki gem server adresini https den http olarak değiştirdim.

TakipApp/Gemfile

source 'http://rubygems.org'

git_source(:github) do |repo_name|
...

Bakalım uygulama çalışıyor mu? Konsolda şunları girelim sırayla,

cd TakipApp
bundle
rails s

Artık http://localhost:3000 adresini tarayıcıda açınca Rails yeni uygulama başlangıç sayfası gelmiş olmalı,


Bu kadarını yapmayı başardıysak bundan sonrası çok kolay. Demek isterdim tabi, ama buraya gelince "yürümeye başladım, hadi koşayım" demek geliyor içimden. 


Firmalar Tablosu

İlk tablomuzda firmaların bilgilerini saklayalım. Konsolda Ctrl+C tuşlayıp server'ı durdurduktan sonra, tablomuzu oluşturmak için şu satırı girelim,


rails g scaffold Company name:string address:string taxOffice:string taxNumber:string webSite:string logo:string note:string

Companies tablosu firmalara ait bilgileri barındırıyor. name sütununda firma ismi, address sütununda firma adresi, taxOffice sütununda vergi dairesi, taxNumber sütununda vergi numarası, webSite sütununda firma web sitesi adresi, logo sütununda firma logosuna ait resim dosyasının adı ve note sütununda da firmaya ait ne not almak istersek yazarız. 

Veri tabanına tabloyu eklemek için migrate komutu çalıştıralım ve server'ı tekrar başlatalım.

rails db:migrate
rails s

Tarayıcıda http://localhost:3000/companies adresini açtığımızda Rails'in bizim için hazırladığı sayfayı görürüz.


Görünümü düzenlemeye geçmeden önce birkaç test verisi girelim. 




Bootstrap CSS ile Güzelleştirelim

Server'ı durduralım. Bootstrap CSS kütüphanesini kullanmak için Gemfile dosyamıza şu satırları ekliyoruz,

TakipApp/Gemfile
gem "bootstrap-sass"
gem "jquery-rails"

Arkasından konsolda ,

bundle

yazarak Bootstrap CSS kütüphanesi ve jQuery JavaScript kütüphanesini uygulamamıza ekliyoruz. Bootstrap kullanmak için yapılacak bir şey daha var application.css dosyası adını. application.scss olarak değiştirdikten sonra içine ilave şunları giriyoruz,

app/assets/stylesheets/application.scss
@import "bootstrap-sprockets";
@import "bootstrap";

Ayrıca default stillerden kurtulmak için 

 *= require_tree .
 *= require_self

Saturlarını siliyoruz.

jQuery kütüphanesini kullanabilmek için de application.js dosyasına şu satırları ekliyoruz,

app/assets/javascript/application.js
//= require jquery
//= require jquery_ujs
//= require bootstrap-sprockets

Şimdi server'ı tekrar çalıştırıp sayfayı yenilersek Bootstrap CSS etkisini Yazılarda görürüz. Tabi bu yetmiyor, şimdi görselimizi biraz düzenleyelim.

Başlıktan başlayalım, index.html.erb dosyasındaki başlık şöyle

app/views/companies/index.html.erb
<h1>Companies</h1>
Bu başlığı ve en alttaki newCompany linkini birleştirelim
<div class="row">
  <div class="col-sm-4"><h1>Firmalar</h1></div>
  <div class="col-sm"><%= link_to 'Yeni firma', new_company_path, class: "btn btn-primary", style: "margin: 20px;" %></div>
</div>

Başlığı ve yeni firma ekleme linkini aynı row içine alıp yan yana gösteriyoruz.


Şimdilik yazı kenara çok yakın ama sebebi bir container içine konmaması. Onu az sonra layout üzerinden yapacağız. Burada Başlığı ve yeni firma linkini aynı satırın içine yerleştirip, linki de butona benzetmek için Bootstrap class tanımlarını kullanıyoruz. 

Sıra geldi table görünümüne. Tabloyu önce bir row içine alıp, görünümü de Bootstrap table olarak değitiriyoruz. 

app/views/companies/index.html.erb
<div class="row">
  <table class="table">
    <thead>
      <tr>
        <th>İsim</th>
        <th>Adres</th>
        <th>Vergi Dairesi</th>
        <th>Vergi No</th>
        <th>Web Sitesi</th>
        <th>Logo</th>
        <th colspan="2"></th>
      </tr>
    </thead>

    <tbody>
      <% @companies.each do |company| %>
        <tr>
          <td><%= link_to company.name, company %></td>
          <td><%= company.address %></td>
          <td><%= company.taxOffice %></td>
          <td><%= company.taxNumber %></td>
          <td><%= link_to company.webSite, company.webSite, target: "_blank" %></td>
          <td><%= image_tag company.logo, style: "height: 70px; width: auto; max-width: 150px;" %></td>
          <td><%= link_to 'Düzenle', edit_company_path(company), class: "btn btn-primary" %></td>
          <td><%= link_to 'Sil', company, method: :delete, data: { confirm: "Firma " + company.name + " silinecek emin misin?" }, class: "btn btn-danger" %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
Neler yaptık neler. Önce not sütununu bu görünümden çıkardık. Notları merak eden ayrıntıya baksın. Sonra sütun başlıklarını Türkçe'ye çavirdik. Orjinalde olan Show linkini kaldırıp, firma ismina tıklanınca ayrıntıya gidilmesini sağladık. Firma web sitesi bilgisini link haline getirdik ve tıklanınca yeni sekmede açılmasını sağladık. Firma logo bilgisini resmi gösterecek şekilde ayarladık. Logo bilgisine örnek değerler girerken /images/firma1.png gibi isimler vermiştim. Bu logo resimlerini uygulamamızın public klasörü altında images adında yeni bir klasör ekleyerek oraya koyuyoruz. Bunu şimdilik el ile yaptım uygulama içinden dosya yükleme falan uğraşmadım. Firmaların kendi web sitelerinde logo resimlerine ait link varsa o da kullanılabilir. Kayıt düzenleme linklerinden Edit için mavi, Destroy için de kırmızı bir buton yakışır dedik. En son görünüm şöyle oldu.


Kenarlara sıra şimdi geldi. Layout üzerinde biraz oynayalım ve uygulamamızın ana yerleşimini belirleyelim. 

app\views\layouts/application.html.erb
  <body>
  	<nav class="navbar navbar-default">
  		<a href="http://www.turkpoem.com" class="navbar-brand" target="_blank">POEM</a>
      <a href="/companies" class="btn btn-success">Firmalar</a>
  	</nav>
  	<div class="container">
	    <%= yield %>
  	</div>
  </body>
Yukarıya bir nav-bar koyup içine sayfalarımızın linklerini koymaya başlıyoruz. Uygulama ilerledikçe ilaveler gelecek. Ben banner kısmına kendi firmamın linkini koydum, belki ilerde uygulamamıza bir dashboard yapıp oraya bağlarız. Son görünüm şöyle oldu,


Temel görünümü baya bi oturttuk. Sıra geldi firmalara ait new , edit ve show sayfalarının görünümlerine. Yukarıdaki Yeni firma butonuna tıklayınca http://localhost:3000/companies/new sayfası açılır. Sayfa şu anda Rails default yapısı neyse öyle duruyor. Bu sayfa iki parçadan oluşur, biri app/views/companies/new.html.erb dosyası diğeri de app/views/companies/_form.html.erb parça dosyası. Form dosyası aynen edit sayfasında da kullanıldığı için ortak parça dosya olarak tanımlanmış. Önce new.html.erb dosyasını değiştirelim, burada form hariç sayfa içeriği var.

app/views/companies/new.html.erb
<h1>Yeni firma ekle</h1>

<%= render 'form', company: @company, etiket: "Ekle", logo_txt: "/images/" %>

<%= link_to 'Geri', companies_path, class:"btn btn-primary" %>
Görünüm şöyle oldu,


Sayfaya etiket ve logo_txt adında 2 yeni değişken gönderiyoruz. etiket değişkeni formun submit butonu olan Create Company butonu üzerinde yazan yazıyı tayin edecek. Bu sayfa yeni firma eklemek için olduğundan değişken değeri Ekle olarak girildi, edit sayfasında ise Kaydet değeri vereceğiz. logo_txt değişkeni ise her seferinde forma aynı klasör adını yazmamak için yardımcı bilgi olarak verildi. En son Back linkini bir buton şeklinde gösterip Türkçeleştirdik.

Sıra geldi form parça görüntüsüne,

app/views/companies/_form.html.erb
<%= form_with(model: company, local: true) do |form| %>
  <% if company.errors.any? %>
...

  <div class="form-group col-sm-12">
      <%= form.label "İsim :" %>
      <%= form.text_field :name, id: :company_name, class: "form-control" %>
  </div>

  <div class="form-group col-sm-12">
    <%= form.label "Adres :" %>
    <%= form.text_field :address, id: :company_address, class: "form-control" %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Vergi dairesi" %>
    <%= form.text_field :taxOffice, id: :company_taxOffice, class: "form-control" %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Vergi No :" %>
    <%= form.text_field :taxNumber, id: :company_taxNumber, class: "form-control" %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Web sitesi :" %>
    <%= form.text_field :webSite, id: :company_webSite, class: "form-control" %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Logo :" %>
    <%= form.text_field :logo, id: :company_logo, class: "form-control", value: logo_txt %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label :note %>
    <%= form.text_field :note, id: :company_note, class: "form-control" %>
  </div>

  <div class="form-group col-sm-6">
    <%= image_tag("/images/logo.png", alt: "rss feed", id: "logo-image", style: "width: auto; max-height: 100%; max-width: 100%") %>
  </div>

  <div class="actions form-group">
    <%= form.submit etiket, class: "btn btn-success" %>
  </div>
<% end %>

<%= javascript_tag do %>
  $("#logo-image").attr("src", "<%= logo_txt %>");
  $("#company_logo").change(function(){
    $("#logo-image").attr("src", this.value);
  });
<% end %>
Başlardaki error mesajları ile ilgilenmedim, sadece form görünümü ile uğraştım. Formda class="field" olan div elemanlarını class="form-group col-sm-12" olarak değiştiriyoruz ve Bootstrap form grupları olarak stil veriyoruz. Bir kısmını da col-sm-6 olarak belirleyip bir sırada 2 form elemanı olarak gösteriyoruz. Veri girilen form elemanlarına da class: "form-control" stillendirmesi ekleyerek Bootstrap form kontrol olarak görünmesini sağlıyoruz. logo değerinin girildiği form elemanına default değer olarak yukarıdan gelen logo_txt değişkeni değerini yazıyoruz. 

Forma ilave olarak logo resmi gösterimi ekledik ve bir JavaScript ilavesi ile Logo bilgisi değiştirilince otomatik olarak belirtilen resmin gösterilmesini sağladık. JavaScript kodumuzda jQuery'nin change ve attr fonksiyonlarını kullandık. Görünüm şöyle oldu,




edit sayfasını da şöyle düzenleriz, 

app/views/companies/edit.html.erb
<h1>Firma düzenle</h1>

<%= render 'form', company: @company, etiket: "Kaydet", logo_txt: @company.logo %>

<%= link_to 'Göster', @company, class: "btn btn-primary" %> |
<%= link_to 'Liste', companies_path, class: "btn btn-info" %>
Form submit butonu yazısı Kaydet olarak veriyoruz, logo resmi de edit edilen firma logo değeri oluyor. Görünüm şöyle olur,


Firmalar için bu kadar yeter. Sırada firmalarda çalışan kişilere ait bilgilerin kaydedildiği People tablosu var. Hadi bakalım..



Kişiler Tablosu

Kişiler tablomuz, veritabanı tasarımımıza göre kişinin ismi, çalıştığı firma, email, telefon numarası ve kartvizit resmi bilgilerini içeriyor. Tabloyu oluşturmak için konsolda çalıştıracağımız scaffold komutu şöyle,  
rails g scaffold Person name:string email:string phone:string note:string card:string company:belongs_to
tabi arkasından tabloyu veritabanında oluşturması için ,
rails db:migrate
Server'ı çalıştırıp http://localhost:3000/people adresini tarayıcıda açtığımızda Kişiler listesi sayfasının default halini görürüz. 


Bu sayfada New Person linkine tıklayıp örnek kişiler eklemek istesek , açılan default formda firmanın id'sini veri olarak girmemiz gerekir. Bu zorlukla uğraşmamak için görünüm düzenlemeye index sayfasından değil formdan başlasak daha iyi olacak. 

Önce layout içinde bulunan menü linklerine Kişiler linkini ekleyerek başlayalım.

app/views/layout/application.html.erb
 ...
 <body>
  	<nav class="navbar navbar-default">
  		<a href="http://www.turkpoem.com" class="navbar-brand" target="_blank">POEM</a>
      <a href="/companies" class="btn btn-success">Firmalar</a>
      <a href="/people" class="btn btn-success">Kişiler</a>
  	</nav>
...
Sayfayı yenileyince Kişiler linkinin de yukarıdaki menüye eklendiğini görürüz. Companies görsellerinde yaptığımız aynı düzenlemeleri new ve edit sayfalarında yapalım.

app/views/people/new.html.erb
<h1>Yeni kişi ekle</h1>

<%= render 'form', person: @person, etiket: "Ekle", card_txt: "/cards/" %>

<%= link_to 'Geri', people_path, class:"btn btn-primary" %>
Koddan gördüğümüz üzere kartvizit resimlerini bu sefer public/cards/ klasöründe saklayacağız.

app/views/people/edit.html.erb
<h1>Kişi Düzenleme</h1>

<%= render 'form', person: @person, etiket: "Kaydet", card_txt: @person.card %>

<%= link_to 'Göster', @person, class: "btn btn-primary" %> |
<%= link_to 'Liste', people_path, class: "btn btn-info" %>
Forma da önce Companies formunda yaptıklarımızı yapalım.

app/views/people/_form.html.erb
<%= form_with(model: person, local: true) do |form| %>
  <% if person.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(person.errors.count, "error") %> prohibited this person from being saved:</h2>

      <ul>
      <% person.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="form-group col-sm-12">
    <%= form.label "İsim :" %>
    <%= form.text_field :name, id: :person_name, class: "form-control" %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label :email %>
    <%= form.text_field :email, id: :person_email, class: "form-control" %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Telefon :" %>
    <%= form.text_field :phone, id: :person_phone, class: "form-control" %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Firması :" %>
    <%= form.text_field :company_id, id: :person_company_id, class: "form-control" %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Kartvizit :" %>
    <%= form.text_field :card, id: :person_card, class: "form-control", value: card_txt %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Notlar :" %>
    <%= form.text_field :note, id: :person_note, class: "form-control" %>
  </div>

  <div class="form-group col-sm-6">
    <%= image_tag("/cards/umit_kayacik.jpg", alt: "person card", id: "card-image", style: "width: auto; max-height: 100%; max-width: 100%") %>
  </div>

  <div class="actions form-group">
    <%= form.submit etiket, class: "btn btn-success" %>
  </div>
<% end %>

<%= javascript_tag do %>
  $("#card-image").attr("src", "<%= card_txt %>");
  $("#person_card").change(function(){
    $("#card-image").attr("src", this.value);
  });
<% end %>
Sıralamada notları en sona aldık ve firmayı daha öne çektik. Formu bu şekliyle bırakırsak dediğim gibi firma için id değeri girmemiz gerekir. Bunun yerine bir dropdown liste olsa da oradan firma seçimini yapsak ne güzel olur. bu amaçla formun firma kısmını şöyle değiştiriyoruz.

app/views/people/_form.html.erb
...
  <div class="form-group col-sm-6">
    <%= form.label "Firması :" %>
    <%= form.collection_select(:company_id, Company.all, :id, :name, {:include_blank => true},
        {class: "form-control"}) %>
  </div>
...
Dropdown tanımlama parametreleri şöyle olur: ilk parametre seçilen yazıya karşı gelen değerin formda hangi sütun bilgisini içerdiği. İkinci parametre ise listede olacak kolleksiyon bilgisi, burada tüm firmalar veri tabanından çekileceği belirtilmiş. İstersek burada firmaların listesini çekerken isim ya da id'ye bağlı sıralı olmasını da belirtebiliriz. 3. parametre formda seçili yazıya karşılık forma gidecek değerin kolleksiyondaki karşılığı, yani burada seçilen Company.id değeri formda değer olarak işlenecek. 4. parametre kolleksiyondan neyin listede görsel olarak verildiği, yani Company.name (firma isimleri) listede görünecek. 5. parametre opsiyonlar süslü parantez içinde belirtilmiş, burada en üstte bir boş seçeneği bırakılması istendi. Boş satırı koymazsak yeni kişi eklemek istediğimizde seçime default olarak listenin en başındaki firma gelir. Son parametre ise html opsiyonlarını içerir. 

Yaşasın artık listemize örnek birkaç kişi ekleyebiliriz. 


Örnek kişiler ekleyip index sayfamıza geri gelelim.


Sıra geldi index.html.erb görselini düzenlemeye,

app/views/people/index.html.erb
<p id="notice"><%= notice %></p>

<div class="row">
  <div class="col-sm-4"><h1>Kişiler</h1></div>
  <div class="col-sm"><%= link_to 'Yeni kişi', new_person_path, class: "btn btn-primary", style: "margin: 20px;" %></div>
</div>

<div class="row">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>İsim</th>
        <th>Firması</th>
        <th>Email</th>
        <th>Telefon</th>
        <th>Kartvizit</th>
        <th colspan="2"></th>
      </tr>
    </thead>

    <tbody>
      <% @people.each do |person| %>
        <tr>
          <td><%= link_to person.name, person %></td>
          <td><%= link_to person.company.name, person.company %></td>
          <td><%= mail_to person.email %></td>
          <td><%= person.phone %></td>
          <td><%= image_tag person.card, style: "height: 70px; width: auto; max-width: 150px;" %></td>
          <td><%= link_to 'Düzenle', edit_person_path(person), class: "btn btn-primary" %></td>
          <td><%= link_to 'Sil', person, method: :delete, data: { confirm: person.name + ' kişisi silinecek emin misin?' }, class: "btn btn-danger" %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
Neler yaptık? Standart Bootstrap güzelleştirmemizi yaptık. Kişi adından link ile kişi ayrıntılarına gitmesini sağladık. Firma adına tıklanınca firma ayrıntısına gitmesini sağladık. Email adresine tıklanınca otomatik olarak mail hazırlamak için link oluşturduk. Kartvizitinin de küçük bir resmini koyduk. Keşke telefonuna tıklayınca da cep telefonuma kumanda edip otomatik aranmasını sağlasa, ama bu konuda daha benim bildiğim Rails komutu yok. 

Kişilerde son olarak show.html.erb düzenlemesi kaldı,

app/views/people/show.html.erb
<p id="notice"><%= notice %></p>

<div class="row">
  <div class="col-sm-8">
    <p>
      <strong class="col-sm-3">İsim :</strong>
      <%= @person.name %>
    </p>

    <p>
      <strong class="col-sm-3">Firması :</strong>
      <%= @person.company.name %>
    </p>

    <p>
      <strong class="col-sm-3">Email :</strong>
      <%= @person.email %>
    </p>

    <p>
      <strong class="col-sm-3">Telefon :</strong>
      <%= @person.phone %>
    </p>

    <p>
      <strong class="col-sm-3">Kartvizit :</strong>
      <%= @person.card %>
    </p>

    <p>
      <strong class="col-sm-3">Notlar :</strong>
      <%= @person.note %>
    </p>
  </div>
  <div class="col-sm-4">
    <img src="<%= @person.card %>" alt="kartvizit", style="width: auto; max-height: 100%; max-width: 100%" />
  </div>
</div>

<%= link_to 'Düzenle', edit_person_path(@person), class: "btn btn-primary" %> |
<%= link_to 'Liste', people_path, class: "btn btn-info" %>
Düzenleme sonrası sayfamız şöyle görünecektir,





Projeler Tablosu

Sıra geldi projeler tablosuna Projeler tablosunda yapacağımız işler Kişiler tablosunda yaptıklarımızla neredeyse bire bir aynı. Bu yüzden ayrıntıları ile vakit kaybetmeyeceğim. Önce konsoldan tablomuzu oluşturuyoruz. 

rails g scaffold Project name:string note:string folder:string company:belongs_to
rails db:migrate

app/views/projects/new.html.erb
<h1>Yeni Proje</h1>

<%= render 'form', project: @project, etiket: "Ekle" %>
<div class="row"></div>
<%= link_to 'Geri', projects_path, class:"btn btn-primary" %>

app/views/projects/_form.html.erb
<%= form_with(model: project, local: true) do |form| %>
  <% if project.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(project.errors.count, "error") %> prohibited this project from being saved:</h2>

      <ul>
      <% project.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="form-group col-sm-8">
    <%= form.label "İsim :" %>
    <%= form.text_field :name, id: :project_name, class: "form-control" %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Firması :" %>
    <%= form.collection_select(:company_id, Company.all, :id, :name, {:include_blank => true}, {class: "form-control"}) %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Klasör :" %>
    <%= form.text_field :folder, id: :project_folder, class: "form-control" %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Notlar :" %>
    <%= form.text_field :note, id: :project_note, class: "form-control" %>
  </div>

  <div class="actions form-group col-sm-8">
    <%= form.submit etiket, class: "btn btn-success" %>
  </div>
<% end %>

app/views/projects/edit.html.erb
<h1>Proje Düzenleme</h1>

<%= render 'form', project: @project, etiket: "Kaydet" %>

<div class="row"></div>
<%= link_to 'Göster', @project, class: "btn btn-primary" %> |
<%= link_to 'Liste', projects_path, class: "btn btn-info" %>


app/views/projects/show.html.erb
<p id="notice"><%= notice %></p>

<div class="row">
  <div class="col-sm-10">
    <p>
      <strong class="col-sm-2">İsim :</strong>
      <%= @project.name %>
    </p>

  <p>
    <strong class="col-sm-2">Firma :</strong>
    <%= @project.company.name %>
  </p>

  <p>
    <strong class="col-sm-2">Klasör :</strong>
    <%= @project.folder %>
  </p>

  <p>
    <strong class="col-sm-2">Not :</strong>
    <%= @project.note %>
  </p>
  </div>
</div>

<%= link_to 'Düzenle', edit_project_path(@project), class: "btn btn-primary" %> |
<%= link_to 'Liste', projects_path, class: "btn btn-info" %>


Proje show sayfasında gösterimi col-sm-10 sınıfında bir div içine aldık. İlerleyen kısımlarda sağda kalan 2 sütınluk alanı başka bir gösterim için kullanacağız. Ben tabi bu yazıyı bitmiş projeden yazdığım için geleceği tahmin etme yeteneğine sahibim..

app/views/projects/index.html.erb
<p id="notice"><%= notice %></p>

<div class="row">
  <div class="col-sm-4"><h1>Projeler</h1></div>
  <div class="col-sm"><%= link_to 'Yeni Proje', new_project_path, class: "btn btn-primary", style: "margin: 20px;" %></div>
</div>

<div class="row">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>İsim</th>
        <th>Firma</th>
        <th>Klasör</th>
        <th>Notlar</th>
        <th colspan="2"></th>
      </tr>
    </thead>

    <tbody>
      <% @projects.each do |project| %>
        <tr>
          <td><%= link_to project.name, project %></td>
          <td><%= link_to project.company.name, project.company %></td>
          <td><%= project.folder %></td>
          <td class="col-sm-3"><%= project.note %></td>
          <td><%= link_to 'Düzenle', edit_project_path(project), class: "btn btn-primary" %></td>
          <td><%= link_to 'Sil', project, method: :delete, data: { confirm: project.name + 'projesi silinecek emin misin??' }, class: "btn btn-danger" %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>

<br>

Ve son olarak menü barda projeler için link ilavesi,

app/views/layouts/application.html.erb
...
  <body>
  	<nav class="navbar navbar-default">
  		<a href="http://www.turkpoem.com" class="navbar-brand" target="_blank">POEM</a>
      <a href="/companies" class="btn btn-success">Firmalar</a>
      <a href="/people" class="btn btn-success">Kişiler</a>
      <a href="/projects" class="btn btn-success">Projeler</a>
  	</nav>
...
Projeler şimdilik bu kadar. Ama ileride tekrar döneceğiz.


Proje Kişileri Ara Tablosu

Sıra geldi projeler ile ilgili firmanın o projeyle ilgili görevlilerini iliştireceğimiz ProjectPerson tablosuna. Bu tablo sadece projeler ve kişiler tablolarına bağlantılar içeriyor. Bu tablo ana menüde yer almayacak, proje görselinde ilaveler yaparak o projenin ilgili kişilerinin bir listesini oluşturması için kullanıcıya imkan vereceğiz. 

Konsol komutlarıyla tabloyu oluşturarak başlıyoruz,
rails g scaffold ProjectPerson project:belongs_to person:belongs_to
rails db:migrate

Server'ı çalıştırıp http://localhost:3000/project_people sayfasını tarayıcıda açınca bu tabloyu görürüz. Bu tablo görsellerinde sadece örnek veriler falan girmek için basit değişimler yaptım. 

app/views/project_people/index.html.erb
<p id="notice"><%= notice %></p>

<h1>Project People</h1>

<table class="table">
  <thead>
    <tr>
      <th>Project</th>
      <th>Person</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @project_people.each do |project_person| %>
      <tr>
        <td><%= project_person.project.name %></td>
        <td><%= project_person.person.name %></td>
        <td><%= link_to 'Show', project_person %></td>
        <td><%= link_to 'Edit', edit_project_person_path(project_person) %></td>
        <td><%= link_to 'Destroy', project_person, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Project Person', new_project_person_path %>

app/views/project_people/new.html.erb
<h1>New Project Person</h1>

<%= render 'form', project_person: @project_person, etiket: "Ekle" %>

<%= link_to 'Back', project_people_path %>

app/views/project_people/edit.html.erb
<h1>Editing Project Person</h1>

<%= render 'form', project_person: @project_person, etiket: "Kaydet" %>

<%= link_to 'Show', @project_person %> |
<%= link_to 'Back', project_people_path %>

Form biraz ekşınlı olacak. İsteriz ki, proje dropdowndan seçilsin ve proje seçilince kişiler seçimine sadece o projenin ait olduğu firmanın çalışanları gelsin. İşte bu biraz karışık bir iş. Burada kullandığım yöntemi karışık bulduğum için ileride benzer yerlerde full JavaScript kullanarak işi çözdüm. Ama bu yolu da sol kulağımızı sağ elle tutmak şekli olarak gösterelim. 

app/views/project_people/_form.html.erb
<%= form_with(model: project_person, local: true) do |form| %>
  <% if project_person.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(project_person.errors.count, "error") %> prohibited this project_person from being saved:</h2>

      <ul>
      <% project_person.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="form-group col-sm-6">
    <%= form.label "Proje :" %>
    <%= form.collection_select(:project_id, 
        Project.all, :id, :name, 
        {:include_blank => true}, 
        {class: "form-control",
          id: "project-select",
        :"data-remote" => "true",   # UJS içinmiş
        :"data-url" => url_for(controller: "project_people", action: "getData"),                # burada veriyi istiyoruz
        :"data-type" => "json",      # jQuery ile dönen veriyi parse etmek için
          # bu select seçim yapıldığı anda ajax çağrısını çakar
        }) %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Kişi :" %>
    <%= form.collection_select(:person_id, Person.all, :id, :name,
        # bu selectin değerleri proje seçimi değişince değişecek
      {:include_blank => true}, 
      {class: "form-control",
        id: "second-select"}) %>
  </div>

  <div class="actions form-group">
    <%= form.submit etiket, class: "btn btn-success" %>
  </div>
  </div>
<% end %>

Bu şekliyle çalıştırırsak Rails hata mesajı vereck, çünkü yapacaklarımız var. ne yaptık bakalım. Proje seçimi için bir dropdown koyuyoruz ve içine tüm projelerin bir listesini koyuyoruz. Seçimin data-remote özelliğine true değer verdiğimizde seçim değişince bir ajax çağrısı yapıyor. data-url özelliği ajax çağrısının yapılacağı adresi belirliyor, yani seçim değişince project-people kontrolöründe getData metoduna bir ajax çağrısı yapılıyor. data-type özelliğine json değeri vererek, yapılan çağrıdan bir json veri dönüşü beklediğimizi belirtiyoruz. 

Demek ki project_people kontrolörüne getData adında bir metod ekleyeceğiz ve seçilen projenin firmasında çalışan kişilerin bir listesini döneceğiz. 

app/controllers/project_people_controller.rb
...
    def getData
      @data_from_project_select = project_person_params["project_id"] # seçilen proje id'si
      @data_for_person_select = Project.find(@data_from_project_select).company.people.all
        # kişi seçimi iin o projenin firmasındaki kişileri topla
      render json: @data_for_person_select.map{|p| [p.id, p.name]} # json olarak çağrıya dönüş yap
    end
...

Bu metodu kontrolör içinde private satırının hemen üzerine koyabiliriz. Belki de altına koymalıyız ama güvenlik beni bağlamıyor, uygulamayı internete koymayı düşünmüyorum. 

Ne yapar bu metod? Dropdown çağrıya veri olarak kendinde seçilen değeri yani project_id değerini gönderecek. Metod da o projenin firmasının tüm çalışanlarının bir listesini json data olarak geri dönüyor.

Metodu koymak yetmez, routes.rb içinde bir ilave ile bu metoda istek yapılabileceğini Rails'e haber vermemiz lazım. 

config/routes.rb
Rails.application.routes.draw do
  resources :project_people do
    collection do
      get "getData"
    end
  end
  resources :projects
  resources :people
  resources :companies
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Bu değişikliği yaptıktan sonra tarayıcımızın geliştirici araçları penceresinde network hareketini izleyince, bu dropdown değeri değiştiğinde çağrının yapıldığını ama cevabın gelmeyip Company sınıfında people değerinin tanınmadığını belirten bir mesaj görürüz. Neden oldu? Biz kişiler tablosunu oluştururken companies tablosuna belongs_to ile bağlı olduğunu belirttik. Ama demek ki companies tablosu daha önce tanımlanmış olduğu için onun modeline firmaya bağlı bir çok kişi olabileceği otomatik eklenmemiş. Hemen modeli açalım ve şu satırları ekleyelim. 

app/models/company.rb
class Company < ApplicationRecord
	has_many :people
	has_many :projects
end

Demek ki neymiş, belongs_to ile tablo ürettin mi bağlı tabloya has_many satırlarını manual ekleyeceksin. 

Artık proje değiştirince bağlı olduğu firmanın kişilerinin listesinin geldiğini network'de görebiliriz. Şimdi bu gelen listeyi kişi seçimine uygulamak için client tarafta JavaScript'ten başka çare yooook. JavaScript kodu istersek sayfa görseline ekleriz, ama görsel ile kodu karıştırmayalım taraftarları demiş application.js içine koyalım. Bana kalsa görsel içine eklerim, bilmem nerde bir JavaScript kod varmış, bilmem neyi bilmem ne yapıyormuş, benim kafam karışıyor. Ama neyse Google ile kod yazıyoz nasıl olsa, ustalar ne derse öyle olsun.

app/assets/javascripts/application.js
//= require bootstrap-sprockets

$(document).ready(function(){
	// ajax request başarılı olduysa
	$("#project-select").on("ajax:success", function(evt, xhr, settings){
		// ikinci select elemanını seç
		var secondSelect = $("#second-select");
		//içini boşalt
		secondSelect.empty();
		// gelen data id ve name olarak gelecekti
		$.each(evt.detail[0], function(index, value){
			// bir optiomn elemanı oluştur
			var opt = $("<option/>");
			// gelen data [id, name] şeklinde olacaktı
			opt.attr("value", value[0]);
			opt.text(value[1]);
			// option elemanını select'e ekle
			opt.appendTo(secondSelect);
		});
	});
});

Bu şekilde çalıştırana kadar bayağı bi uğraştım. Sonra bu tekniği kullanmayacağım. Belki çok büyük bir hata yaptım ama sallayamayacağım.. Listemizde örnek olması amacıyla birkaç veri girdiğimizde index sayfası görünümü şöyle olacaktır.



Dediğim gibi, bu tabloyu ana menülerde göstermeyeceğiz. Bu yüzden minimum düzenleme yapıp bıraktık. Şimdi projeler tablosunun show görselinde ilgili proje kişilerini gösterelim ve yine aynı sayfada projeye yeni kişi eklenmesi ya da çıkarılması için ilaveler yapalım. 

Görselin en altına şunları ekleyelim,

app/views/projects/show.html.erb
...
<%= link_to 'Düzenle', edit_project_path(@project), class: "btn btn-primary" %> |
<%= link_to 'Liste', projects_path, class: "btn btn-info" %>


<div class="row">
  <div class="col-sm-4">
    <h3>İlgili Kişiler</h3>
    <ul>
    <% @project.project_people.each do |project_person| %>
      <li>
        <%= link_to project_person.person.name, project_person.person %>
        <%= link_to "-", "destroyPerson?id=" + project_person.id.to_s, class: "btn btn-sm" %>
      </li>

    <% end %>
    <%= form_with(url: "addPerson", remote: true) do |form| %>
        <%= form.collection_select :person_id, @project.company.people.all, :id, :name, { :include_blank => true } %>
        <%= form.hidden_field :project_id, value: @project.id %>
        <%= form.submit '+', { class: "btn" } %>
    <% end %>
    </ul>
  </div>

  <div class="col-sm-8">
  </div>
</div>

Ne yapıyoruz? Görselin altına yeni bir satır açıyoruz. Satırın soldaki 4 sütunluk bölümünde proje ile ilişkilendirilen kişilerin bir listesini yayınlıyoruz. Her kişinin üzerine tıklanınca ayrıntısına gidilebiliyor. Her kişinin yanına "-" yazılı bir buton koyuyoruz bu buton tıklanınca destroyPerson metodu ile ilgili kişinin proje ile bağını siliyoruz. destroyPerson metodu şu anda yok , kontrolör içinde tanımlayacağız. Daha sonra küçük bir form oluşturuyoruz. Formda projenin ait olduğu firma çalışanlarının bir listesi olan dropdown var ki bu form gönderilirken bu seçim person_id parametresi ile gönderilecek. Bir görünmez alanda projenin id değerini de formla beraber göndermek gerekti, onu da ekledim. Formda bir de submit butonu var. Form addPerson isimli bir metoda gönderilecek, dolayısıyla bu metodu da kontrolöre eklemek gerekiyor. En son 8 sütunluk bir bölge ayrılmış ve boş bırakılmış. Daha sonra buraya proje için düzenlediğimiz faturaların listesi gelecek.

Burada ilk verilecek hata @project.project_people_each satırından gelecek. Ne demiştik belongs_to verdiysek has_many'leri biz ekleyeceğiz. person ve project modellerinin ikisine de bu satırları ekleyelim. 

app/models/person.rb
class Person < ApplicationRecord
  belongs_to :company
  has_many :project_people
end

app/models/project.rb
class Project < ApplicationRecord
  belongs_to :company
  has_many :project_people
end

Sırada metodların kontrolöre eklenmesi var.

app/controllers/projects_controller.rb
...
  def addPerson
    redirect_to controller: "project_people", action: "create_from_project",
      person_id: params["person_id"], project_id: params["project_id"]
  end

  def destroyPerson
    redirect_to controller: "project_people", action: "destroy_from_project",
      id: params["id"]
  end
...

Tabi yeni metodlar için routes.rb de değişmeli. 

config/routes.rb
...
  resources :projects do
    collection do
      post "addPerson"
      get "destroyPerson"
    end
  end
  resources :people
  resources :companies
...

addPerson metodu form tarafından gönderildiği için POST olarak destroyPerson ise bir link bağlantısı olduğu için GET olarak değerlendirilmeli. Tabi bu her zaman böyle değil, standart yapı kullanırsak böyle, yoksa biz parametrelerle oynayarak istediğimiz çeşit çağrı yapabiliriz. 

Metodlar tanımlandıktan sonra görüntü gelecektir. Ama butonlarımız hala çalışmıyorlar.



Butonlar çalışmıyor çünkü, mesela "+" butonuna basınca projects kontrolöründe addPerson metodu çağrılıyor. O da gidiyor project_people kontrolöründe create_from_project metodunu çağırıyor. Yani acayip yapısal davrandık, yoksa sayfadan tıklanınca direk başka kontrolördeki metodu da çağırabilirdik. Neyse canımız öyle istedi diyelim. 

Gidelim project_people kontrolöründeki metod eklemelerine,

app/controllers/project_people_controller..rb
  def create_from_project
    @project_person = ProjectPerson.new(person_id: params["person_id"], project_id: params["project_id"])

    respond_to do |format|
      if @project_person.save
        format.html { redirect_to @project_person.project, notice: 'Project person was successfully created.' }
        format.json { render :show, status: :created, location: @project_person.project }
      else
        format.html { render :new }
        format.json { render json: @project_person.errors, status: :unprocessable_entity }
      end
    end
  end
...
  def destroy_from_project
    @project_person = ProjectPerson.find(params["id"])
    @project = @project_person.project
    @project_person.destroy
    respond_to do |format|
      format.html { redirect_to @project, notice: 'Project person was successfully destroyed.' }
      format.json { head :no_content }
    end
  end
...

Bu kadar şeyi nereden uydurduk? Aslında bunlar create ve destroy metodlarına benzer iş yapıyorlar. Benzer rutinleri isteğimize özel düzenledik. En önemli değişim, proje show görünümüne geri dönüyoruz. Kişi ekleme ya da eksiltmesi yapıldıktan sonra tekrar proje sayfasına dönerek görünümü son bilgilere göre yenilemiş oluyoruz. 

routes.rb içinde bu metodları da tanımlamalıyız.

config/routes.rb
Rails.application.routes.draw do
  resources :project_people do
    collection do
      get "getData"
      get "create_from_project"
      get "destroy_from_project"
    end
  end
  resources :projects do
...


Butonlarımız da çalışmaya başladı. Ne dersiniz ortalık biraz karışmaya başladı di mi? Burada kontrol falan yapmadım. Çünkü olduğunca basitte kalmaya çalışıyorum. Aynı projeye aynı kişiyi defalarca ekleyebilirsiniz ya da kişi seçmeden "+" butonuna basabilirsiniz. Kişiyi listeden çıkarırken de bir soru falan sormadan direk kaydı siliyoruz. Kafa karıştırmamak için bunları koda henüz eklemedim. Hadi devam edelim.

Sırada satış faturalarının kayıt altına alınacağı Sales tablosu var.



Satış Faturaları

Satış faturaları proje doğrultusunda müşteriye kesmiş olduğumuz faturalar. Veri tabanı resmimize bakarak konsoldan satışlar tablomuzu oluşturalım.
rails g scaffold Sales project:belongs_to name:string salesDate:date paymentDate:date
rails db:migrate
Burada ilginç bir şey farkettim. Tekil isim yerine çoğul isim verdim yanlışlıkla. Ama Rails benim hatamı düzeltti ve dosya isimlerini, tabloyu her şeyi ayarladı. Tekil verince çoğul olması gerekenleri ayarladığı gibi çoğul verince de tekil olanları ayarladı. Ne deyim sağ olsun yapanlar, emeği geçenler. Bize pek iş bırakmıyorlar. Tablomuzda faturaya vereceğimiz bir isim, fatura tarihini belirtir bir tarih, ödeme beklediğimiz tarihi belirtir bir tarih ve ilgili olduğu proje bilgileri bulunuyor.

Tarayıcımızda http://localhost:3000/sales sayfasını açtığımızda tablomuza ait default Rails sayfasını görürüz. 


Her şeyden önce bu Satışlar sayfası linkini ana menüye ekleyelim.

app/views/layouts/application.html.erb
...
  <nav class="navbar navbar-default">
    <a href="http://www.turkpoem.com" class="navbar-brand" target="_blank">POEM</a>
    <a href="/companies" class="btn btn-success">Firmalar</a>
    <a href="/people" class="btn btn-success">Kişiler</a>
    <a href="/projects" class="btn btn-success">Projeler</a>
    <a href="/sales" class="btn btn-success">Satışlar</a>
  </nav>
...


index sayfası düzenlemesi ile başlayalım

app/views/sales/index.html.erb
<p id="notice"><%= notice %></p>

<div class="row">
  <div class="col-sm-4"><h1>Satışlar</h1></div>
  <div class="col-sm"><%= link_to 'Fatura Ekle', new_sale_path, class: "btn btn-primary", style: "margin: 20px;" %></div>
</div>

<div class="row">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Proje</th>
        <th>İsim</th>
        <th>Satış Tarihi</th>
        <th>Ödeme Tarihi</th>
        <th colspan="2"></th>
      </tr>
    </thead>

    <tbody>
      <% @sales.each do |sale| %>
        <tr>
          <td><%= link_to sale.project.name, sale.project %></td>
          <td><%= link_to sale.name, sale %></td>
          <td><%= sale.salesDate %></td>
          <td><%= sale.paymentDate %></td>
          <td><%= link_to 'Düzenle', edit_sale_path(sale), class: "btn btn-primary" %></td>
          <td><%= link_to 'Sil', sale, method: :delete, data: { confirm: sale.name + ' faturası silinecek emin misin?' }, class: "btn btn-danger" %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>

<br>

Standart düzenlemeler. Fatura görseline link, Faturanın ait olduğu projeye bir link. İsterseniz müşteri firma adı da gösterilebilir. 

Böyle herşeye İngilizce isim veriyorum diye bi yerlerden tercüme ettiğimi sanmayın. Eskiden kalma alışkanlık , Türkçe problemi çok yaşıyorum diye programlarda bazen yorumları bile İngilizce yazıyorum. 

Sıra geldi new ve edit görsellerine,

app/views/sales/new.html.erb
<h1>Yeni Fatura</h1>

<%= render 'form', sale: @sale, etiket: "Ekle" %>
<div class="row"></div>
<%= link_to 'Geri', sales_path, class:"btn btn-primary" %>


app/views/sales/edit.html.erb
<h1>Fatura Düzenleme</h1>

<%= render 'form', sale: @sale, etiket: "Kaydet" %>

<div class="row"></div>
<%= link_to 'Göster', @sale, class: "btn btn-primary" %> |
<%= link_to 'Liste', sales_path, class: "btn btn-info" %>

Form biraz daha karışık olacak. Önce firma seçilecek, seçilen firmanın projeleri listeye gelecek ve o projelerden biri seçilecek.

app/views/sales/_form.html.erb
<%= form_with(model: sale, local: true) do |form| %>
  <% if sale.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(sale.errors.count, "error") %> prohibited this sale from being saved:</h2>

      <ul>
      <% sale.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="form-group col-sm-8">
    <%= form.label "Firması :" %>
    <%= form.collection_select("company_id", Company.all, :id, :name, 
      {:include_blank => true, 
        selected: @sale.project.nil? ? nil : @sale.project.company.id}, 
      { class: "form-control", id: "company-select" }) %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Projesi :" %>
    <%= form.collection_select(:project_id, @sale.project.nil? ? Project.all : Project.where(company_id: @sale.project.company_id), :id, :name, 
      { include_blank: true }, 
      { class: "form-control", id: "project-select" }) %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "İsim :" %>
    <%= form.text_field :name, id: :sale_name, class: "form-control" %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Fatura Tarihi :" %><br/>
    <%= form.date_select :salesDate, id: :sale_salesDate, 
        :start_year => 2016, 
        :end_year => 2030 %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Ödeme Tarihi" %><br/>
    <%= form.date_select :paymentDate, id: :sale_paymentDate, 
        :start_year => 2016, 
        :end_year => 2030 %>
  </div>

  <div class="actions form-group col-sm-8">
    <%= form.submit etiket, class: "btn btn-success" %>
  </div>
<% end %>

<%= javascript_tag do %>
  $("#company-select").change(function(){
    $.ajax({url: "/companies/getProjects?id=" + this.value, success: function(result){
      var project_select = $("#project-select");
      project_select.empty();
      $.each(result, function(index, value){
        var opt = $("<option/>");
        opt.attr("value", value[0]);
        opt.text(value[1]);
        opt.appendTo(project_select);
      });
    }});
  });
<% end %>

Formun başına firma seçimi için id değeri company-select olan bir dropdown ekliyoruz. Burada tüm firma isimlerini yayınlıyoruz. Eğer formumuz edit sayfasından çağırılıyorsa kayıt bir projeye bağlıdır. O zaman bağlı projenin ait olduğu firma dropdown'da seçili olmasını sağlıyoruz. 

Projeleri de benzer şekilde yapıyoruz. Yeni fatura eklenecekse tüm projeler listeye geliyor. Eğer edit sayfasından form çağrılmışsa listeye sadece bağlı projenin ait olduğu firmanın projeleri geliyor. Bu dropdown zaten orjinal olarak bir kayda project_id ile bağlı olduğu için seçili elemanı Rails otomatik olarak bağlıyor, bizim bir şey yapmamıza gerek yok.

Tarih girilen alanların stilini kolay bir şekilde değiştiremediğim için değiştirmeden bıraktım. Sadece seçilebilir yılları 2016-2030 arasına sınırladım. 

Zaten seçili bir proje varsa buraya kadar olan kod proje listesini ilgili firma projeleriyle kısıtlıyor. Ama yeni bir kayıt oluşturuyorsak firma seçildiğinde o firmanın projelerinin listeye gelmesi için en sonda bir JavaScript kodu ekliyoruz. 

Bu kod ne yapıyor? Firma listesinden bir firma seçildiğinde değer değişimini algılıyor ve bir fonksiyon çalıştırıyor. url: "/companies/getProjects?id=" + this.value url değerinde bir ajax çağrısı yapılıyor. Yani mesela id değeri 3 olan firmayı listeden seçmişsek http://localhost:3000/companies/getProjects?id=3 adresine çağrı yapılıyor. Bu çağrıya cevap gelmesi için companies_controller içinde getProjects adında bir metod olmalı ve routes.rb dosyasında da bu route tanımlı olmalı.

Kod daha sonra ajax çağrısına gelen cevaba göre önce project-select listesinin içeriğini silip, sadece bu cevapta gelenleri listeye ekliyor. 

Metodumuzu da kontrolöre ekleyelim,

app/controllers/companies_controller.rb
...
  def getProjects
    render json: Company.find(params["id"]).projects.map{|p| [p.id, p.name]}
  end

  private
...

id değeri verilen firmaya ait projeleri topluyor, id ve name değerlerinden oluşan bir json veri olarak cevap dönüyor. Cevap [[2,"Firma 1 Proje 1"],[3,"Firma 1 Proje 2"]] şeklinde olacaktır

 Route ilavesini de yapalım.

config/routes.rb
...
  resources :people
  resources :companies do
    collection do
      get "getProjects"
    end
  end
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

JavaScript kodumuz gayet güzel çalışyor. Daha önceki data:remote falan kullanana göre hem daha basit hem daha anlaşılır bir kod. 

Son olarak show sayfası görseli var.

app/views/sales/show.html.erb
<p id="notice"><%= notice %></p>

<div class="row">
  <div class="col-sm-10">
    <p>
      <strong class="col-sm-2">Projesi :</strong>
      <%= link_to @sale.project.name, @sale.project %>
    </p>

    <p>
      <strong class="col-sm-2">İsmi :</strong>
      <%= @sale.name %>
    </p>

    <p>
      <strong class="col-sm-2">Fatura Tarihi ::</strong>
      <%= @sale.salesDate %>
    </p>

    <p>
      <strong class="col-sm-2">Ödeme Tarihi :</strong>
      <%= @sale.paymentDate %>
    </p>
  </div>
  <div class="col-sm-2">
  </div>
</div>

<%= link_to 'Düzenle', edit_sale_path(@sale), class: "btn btn-primary" %> |
<%= link_to 'Liste', sales_path, class: "btn btn-info" %>

<hr/>



Fatura Satırları

Fatura satırları tablosundan önce , bağlı olduğu 2 tablo units ve taxes tablolarından başlasak iyi olacak. Units tablosu fatura satırında kullanılacak olan birimlerin isimlerini saklıyor. Konsolda,
rails g scaffold Unit name:string
rails db:migrate
 
Tarayıcımızda http://localhost:3000/units sayfasını açıp temel kullanılan birimleri ekleyelim. Adet, Metre, Saat, Kg birimleri eklediğimizde listemiz şöyle görünecektir.


Bu tablonun görselleri için bir şey yapmamıza gerek yok. Çok nadir düzenleme yapılacak bir tablo bu. İkinci olarak KDV oranlarının kaydedildiği taxes tablosunu oluşturalım. Konsolda,

rails g scaffold Tax name:string value:float
rails db:migrate
Tarayıcımızda http://localhost:3000/taxes sayfasını açtığımızda bu tabloyu görürüz. Bu tabloya da sık kullanılacak olan %0, %8, %9, %18 değerlerini eklediğimizde liste şöyle olacaktır. 



Sıra geldi faturalarımızda yer alacak işlem satırlarının yer aldığı ivoice_lines tablosuna. Konsolda,
rails g scaffold InvoiceLine sale:belongs_to kod:string product:string unitPrice:float qty:float unit:belongs_to tax:belongs_to
rails db:migrate

Niye kod adında bir sütun koydum, hala düşünüyorum. http://localhost:3000/invoice_lines adresini açıp deneme için bir satır ilavesi yapalım. Şu anda form düzenlememiz olmadığı için tüm belongs_to değerlerini ilgili tablolardan id olarak girmemiz gerekiyor. Aşağıda bir örnek var.



Tekrar listeye dönelim ve görsel düzenlemesine başlayalım.

app/views/invoice_lines/index.html.erb
<p id="notice"><%= notice %></p>

<div class="row">
  <div class="col-sm-4"><h1>Fatura Satırları</h1></div>
  <div class="col-sm"><%= link_to 'Yeni fatura satırı', new_invoice_line_path, class: "btn btn-primary", style: "margin: 20px;" %></div>
</div>

<div class="row">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Kodu</th>
        <th>Satış Faturası</th>
        <th>Ürün</th>
        <th>Fiyatı</th>
        <th>Miktar</th>
        <th>Birim</th>
        <th>Vergi</th>
        <th>Toplam</th>
        <th colspan="2"></th>
      </tr>
    </thead>

    <tbody>
      <% @invoice_lines.each do |invoice_line| %>
        <tr>
          <td><%= invoice_line.kod %></td>
          <td><%= link_to invoice_line.sale.name, invoice_line.sale %></td>
          <td><%= link_to invoice_line.product, invoice_line %></td>
          <td><%= invoice_line.unitPrice %></td>
          <td><%= invoice_line.qty %></td>
          <td><%= invoice_line.unit.name %></td>
          <td><%= invoice_line.tax.name + "-%.2f" % (invoice_line.tax.value * 
              invoice_line.qty * invoice_line.unitPrice) %></td>
          <td><%= "%.2f" % ((invoice_line.tax.value + 1) * invoice_line.qty * invoice_line.unitPrice) %></td>
          <td><%= link_to 'Düzenle', edit_invoice_line_path(invoice_line), class: "btn btn-primary" %></td>
          <td><%= link_to 'Sil', invoice_line, method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-danger" %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>

<br>

Standartın dışında biraz hesap işleri var. Mesela kdv sütuunda kdv ismi ve o değere göre hesaplanan kdv miktarı birleştirilerek gösteriliyor. Sonra satırın vergi dahil toplam değeri için de bir ilave sütun ekledik görsele. Girdiğimiz örnek değerle index sayfamız şöyle görünecek. 




app/views/invoice_lines/show.html.erb
<p id="notice"><%= notice %></p>

<div class="row">
  <div class="col-sm-12">
    <p>
      <strong class="col-sm-3">Satış Faturası :</strong>
      <%= @invoice_line.sale.nil? ? "..." : (link_to @invoice_line.sale.name, @invoice_line.sale) %>
    </p>

    <p>
      <strong class="col-sm-3">Kodu :</strong>
      <%= @invoice_line.kod %>
    </p>

    <p>
      <strong class="col-sm-3">Ürün :</strong>
      <%= @invoice_line.product %>
    </p>

    <p>
      <strong class="col-sm-3">Fiyatı :</strong>
      <%= @invoice_line.unitPrice %>
    </p>

    <p>
      <strong class="col-sm-3">Miktar :</strong>
      <%= @invoice_line.qty %>
    </p>

    <p>
      <strong class="col-sm-3">Birim :</strong>
      <%= @invoice_line.unit.name %>
    </p>

    <p>
      <strong class="col-sm-3">KDV :</strong>
      <%= @invoice_line.tax.name + "-%.2f" % (@invoice_line.tax.value * 
              @invoice_line.qty * @invoice_line.unitPrice) %>
    </p>

    <p>
      <strong class="col-sm-3">Toplam :</strong>
      <%= "%.2f" % ((@invoice_line.tax.value + 1) * @invoice_line.qty * @invoice_line.unitPrice) %>
    </p>
  </div>
</div>

<%= link_to 'Düzenle', edit_invoice_line_path(@invoice_line), class: "btn btn-primary" %> |
<%= link_to 'Liste', invoice_lines_path, class: "btn btn-info" %>

index sayfası gibi burada da toplam değer ilaveleri yaptık. Sıra geldi çetrefilli form görünümüne. Her zaman yaptığımız gibi önce new ve edit ile başlıyoruz. 

app/views/invoice_lines/new.html.erb
<h1>Yeni Fatura Satırı</h1>

<%= render 'form', invoice_line: @invoice_line, etiket: "Ekle" %>
<div class="row"></div>
<%= link_to 'Geri', invoice_lines_path, class:"btn btn-primary" %>

app/views/invoice_lines/edit.html.erb
<h1>Fatura Satırı Düzenleme</h1>

<%= render 'form', invoice_line: @invoice_line, etiket: "Kaydet" %>

<div class="row"></div>
<%= link_to 'Göster', @invoice_line, class: "btn btn-primary" %> |
<%= link_to 'Liste', invoice_lines_path, class: "btn btn-info" %>

Sıra geldi forma. Formda daha önce yaptığımız iki kat içiçe dropdown üstüne bir kat daha geliyor. Firma seçilince projeleri geliyor, proje seçilince projeye ait faturalar geliyor. Gereği var mı bilmem ama antreman olsun bu da,

app/views/invoice_lines/_form.html.erb
<%= form_with(model: invoice_line, local: true) do |form| %>
  <% if invoice_line.errors.any? %>
...
  <% end %>

  <div class="form-group col-sm-8">
    <%= form.label "Firması :" %>
    <%= form.collection_select("company_id", Company.all, :id, :name, 
      {:include_blank => true, 
        selected: @invoice_line.sale.nil? ? nil : @invoice_line.sale.project.company_id}, 
      { class: "form-control", id: "company-select" }) %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Projesi :" %>
    <%= form.collection_select("project_id", @invoice_line.sale.nil? ? Project.all : 
      Project.where(company_id: @invoice_line.sale.project.company_id), :id, :name, 
      { include_blank: true, 
        selected: @invoice_line.sale.nil? ? nil : @invoice_line.sale.project_id }, 
      { class: "form-control", id: "project-select" }) %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Satış Faturası :" %>
    <%= form.collection_select(:sale_id, @invoice_line.sale.nil? ? Sale.all : Sale.where(project_id: @invoice_line.sale.project_id), :id, :name, 
      { include_blank: true,
        selected: @invoice_line.sale.nil? ? nil : @invoice_line.sale.id }, 
      { class: "form-control", id: "sale-select" }) %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Kodu :" %>
    <%= form.text_field :kod, id: :invoice_line_kod, class: "form-control" %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Ürün :" %>
    <%= form.text_field :product, id: :invoice_line_product, class: "form-control" %>
  </div>

  <div class="form-group col-sm-3">
    <%= form.label "Fiyatı :" %>
    <%= form.text_field :unitPrice, id: :invoice_line_unitPrice, class: "form-control" %>
  </div>

  <div class="form-group col-sm-3">
    <%= form.label "Miktar :" %>
    <%= form.text_field :qty, id: :invoice_line_qty, class: "form-control" %>
  </div>

  <div class="form-group col-sm-3">
    <%= form.label "Birimi :" %>
    <%= form.collection_select(:unit_id, Unit.all, :id, :name, {}, 
      { class: "form-control"}) %>
  </div>

  <div class="form-group col-sm-3">
    <%= form.label "KDV :" %>
    <%= form.collection_select(:tax_id, Tax.all, :id, :name, {}, 
      { class: "form-control", id: "invoice_line_tax"}) %>
  </div>

  <div class="actions form-group col-sm-8">
    <%= form.submit etiket, class: "btn btn-success" %>
  </div>
<% end %>

Görselde yaptığımız düzenlemeler ile edit edilirken firma proje ve fatura seçimlerini istediğimiz gibi yaptık. Yeni ekleme yaparken seçe seçe gitmek için de JavaScript ilavesi yapmamız gerekiyor. Ben JavaScript kodunu görselin altına ekleme taraftarıyım, sonra nereye koyduğumu kaybediyorum. Görselin en altına şu JavaScript kodunu ekleyelim.

app/views/invoice_lines/_form.html.erb
...
<%= javascript_tag do %>
  $("#company-select").change(function(){
    if(this.value){
      $.ajax({url: "/companies/getProjects?id=" + this.value, success: function(result){
        var project_select = $("#project-select");
        project_select.empty();
        $.each(result, function(index, value){
          var opt = $("<option/>");
          opt.attr("value", value[0]);
          opt.text(value[1]);
          opt.appendTo(project_select);
        });
        $("<option/>").attr("selected", "selected").attr("value", 0).text("").prependTo(project_select);
      }});
    };
  });

  $("#project-select").change(function(){
    if(this.value){
      $.ajax({url: "/projects/getSales?id=" + this.value, success: function(result){
        var sale_select = $("#sale-select");
        sale_select.empty();
        $.each(result, function(index, value){
          var opt = $("<option/>");
          opt.attr("value", value[0]);
          opt.text(value[1]);
          opt.appendTo(sale_select);
        });
        $("<option/>").attr("selected", "selected").attr("value", 0).text("").prependTo(sale_select);
      }});
    };
  });
<% end %>

companies_controller içinde getProjects metodunu daha önce tanımlamıştık, benzer şekilde projects_controller içinde getSales metodunu da oluşturuyoruz,

app/controllers/projects_controller.rb
...
  def getSales
    render json: Project.find(params["id"]).sales.map{|p| [p.id, p.name]}
  end

  private
...

Tabii ki route eklemesi de yapmalı,

config/routes.rb
...
  resources :projects do
    collection do
      post "addPerson"
      get "destroyPerson"
      get "getSales"
    end
  end
...

Bunları yapınca deneme yaptığımızda hala satış faturaları listesinin proje seçimi değişince değişmediğini görürüz. Konsola bakarsak Rails bir hata mesajı veriyor. NoMethodError (undefined method `sales' for #<Project:0xaff4310>): neden? Tabii ki belongs_do ve has_many meselesi. Proje modeline ilave yapmamışız. 

app/models/project.rb
class Project < ApplicationRecord
  belongs_to :company
  has_many :project_people
  has_many :sales
end

Artık JavaScript kodumuz sağlıklı çalışmaya başladı. 


Proje Ayrıntısına Fatura Listesi Eklenmesi

Fatura satırlarını bu şekil eklemek zahmetli bir iş. Bu işi fatura ayrıntısında yapmak daha anlamlı olacak. Önce kesilen faturaların bir listesini proje ayrıntısına ekleyerek başlıyoruz. Şu 8 sütunluk boşluk bırakmıştık ya en altta oraya bir ilave yapalım.

app/views/projects/show.html.erb
...
  <div class="col-sm-8">
    <strong class="h3">Satış Faturaları</strong>
    <%= link_to '+', new_sale_path + "?project_id=" + @project.id.to_s, class: "btn btn-success", style: "margin: 20px;" %>
      <table class="table table-striped">
        <thead>
          <tr>
            <th>İsim</th>
            <th>Satış Tarihi</th>
            <th>Ödeme Tarihi</th>
            <th>Toplam</th>
          </tr>
        </thead>

        <tbody>
          <% @project.sales.each do |sale| %>
            <tr>
              <td><%= link_to sale.name, sale %></td>
              <td><%= sale.salesDate %></td>
              <td><%= sale.paymentDate %></td>
              <td><%= invoice_total(sale) %></td>
            </tr>
          <% end %>
        </tbody>
      </table>
  </div>
...

Burada görülen invoice_total metodu , faturanın toplam değerini belirleyen metod. Bunu eklemek için helper dosyasını kullanalım da her bi yerden route falan göstermeden erişelim. 

app/helpers/sales_helper.rb
module SalesHelper
    def invoice_total(sale)
        total = 0
        sale.invoice_lines.each do |line|
            total += (line.tax.value + 1) * line.qty * line.unitPrice
        end
        "%.2f" % total
    end
end

Metodu koyduk işimiz bitti zannettik ama sale.invoice_lines hata verdi. Yine bir has_many ilavesi unutulmuş.

app/models/sale.rb
class Sale < ApplicationRecord
  belongs_to :project
  has_many :invoice_lines
end


Artık proje ayrıntı sayfasında o projeye kestiğimiz faturalar görünmeye başladı.




Firma ayrıntılarının gösterildiği sayfayı öylece bırakmışız. O sayfaya da bir el atalım. Firma çalışanları, projeleri ve faturalarına dair listeler ekleyelim. 

app/views/companies/show.html.erb
<p id="notice"><%= notice %></p>

<div class="row">
  <div class="col-sm-8">
    <p>
      <strong class="col-sm-3">İsim:</strong>
      <%= @company.name %>
    </p>

    <p>
      <strong class="col-sm-3">Adres :</strong>
      <%= @company.address %>
    </p>

    <p>
      <strong class="col-sm-3">Vergi dairesi:</strong>
      <%= @company.taxOffice %>
    </p>

    <p>
      <strong class="col-sm-3">Vergi numarası:</strong>
      <%= @company.taxNumber %>
    </p>

    <p>
      <strong class="col-sm-3">Web sitesi:</strong>
      <%= @company.webSite %>
    </p>

    <p>
      <strong class="col-sm-3">Logo :</strong>
      <%= @company.logo %>
    </p>

    <p>
      <strong class="col-sm-3">Notlar :</strong>
      <%= @company.note %>
    </p>
  </div>
  <div class="col-sm-4">
    <img src="<%= @company.logo %>" alt="logo", style="width: auto; max-height: 100%; max-width: 100%" />
  </div>
</div>

<%= link_to 'Düzenle', edit_company_path(@company), class: "btn btn-primary" %> |
<%= link_to 'Liste', companies_path, class: "btn btn-info" %>

<div class="row">
  <div class="col-sm-6">
    <h3>Kişiler</h3>
    <hr/>
    <% @company.people.each do |person| %>
      <p><strong><%= link_to person.name, person %></strong> - <%= mail_to person.email %> - <%= person.phone %></p>
    <% end %>
  </div>
  <div class="col-sm-6">
    <h3>Projeler</h3>
    <hr/>
    <% @company.projects.each do |project| %>
      <p><strong><%= link_to project.name, project %></strong> - <%= project.folder %></p>
    <% end %>
  </div>
</div>

<hr/>

<div class="row">
  <div class="col-sm-6">
    <h3>Satışlar</h3>
    <hr/>
      <table class="table table-striped">
        <thead>
          <tr>
            <th>İsim</th>
            <th>Satış Tarihi</th>
            <th>Ödeme Tarihi</th>
            <th colspan="3"></th>
          </tr>
        </thead>

        <tbody>
          <% @company.projects.each do |project| %>
            <% project.sales.each do |sale| %>
              <tr>
                <td><%= link_to sale.name, sale %></td>
                <td><%= sale.salesDate %></td>
                <td><%= sale.paymentDate %></td>
              </tr>
            <% end %>
          <% end %>
        </tbody>
      </table>
  </div>
  <div class="col-sm-6">
    <h3>Alımlar</h3>
    <hr/>
  </div>
</div>

Artık daha ayrıntılı bir firma görselimiz var.




Kişiler başlığı altında firma çalışanlarının bir listesi var, isimleri, email adresleri ve telefonları. Projeler başlığı altında da firmaya ait projeler bulunuyor. Satışlar başlığı altında da firmaya kestiğimiz tüm faturalar yer alıyor. 

Sırada fatura ayrıntı sayfasında satırların ilaveleri var. Dosyanın altına şunları ekleyelim,

app/views/sales/show.html.erb
...
<%= link_to 'Liste', sales_path, class: "btn btn-info" %>

<hr/>

<div class="row">
  <div class="col-sm-12">
    <strong class="h3">Fatura Satırları</strong>
    <%= link_to '+', new_invoice_line_path + "?sale_id=" + @sale.id.to_s, class: "btn btn-success", style: "margin: 20px;" %>
  </div>
  
  <div class="col-sm-12">
      <table class="table table-striped">
        <thead>
          <tr>
            <th>Kod</th>
            <th>Ürün</th>
            <th>Fiyat</th>
            <th>Miktar</th>
            <th>Birim</th>
            <th>KDV</th>
            <th>Toplam</th>
            <th colspan="2"></th>
          </tr>
        </thead>

        <tbody>
          <% @sale.invoice_lines.each do |invoice_line| %>
            <tr>
              <td><%= invoice_line.kod %></td>
              <td><%= link_to invoice_line.product, invoice_line %></td>
              <td><%= invoice_line.unitPrice %></td>
              <td><%= invoice_line.qty %></td>
              <td><%= invoice_line.unit.name %></td>
              <td><%= invoice_line.tax.name + "-%.2f" % (invoice_line.tax.value * 
              invoice_line.qty * invoice_line.unitPrice) %></td>              
              <td>
                <% total = (invoice_line.tax.value + 1) * invoice_line.qty * invoice_line.unitPrice %>
                <%= "%.2f" % (total) %>
              </td>    
              <td><%= link_to 'Düzenle', edit_invoice_line_path(invoice_line), class: "btn btn-primary" %></td>
              <td><%= link_to 'Sil', invoice_line, method: :delete, data: { confirm: invoice_line.product + ' satırı silinecek emin misin?' }, class: "btn btn-danger" %></td>          
            </tr>
          <% end %>
            <tr>
              <td colspan="5"></td>
              <td><strong>Fatura<br> Toplamı :</strong></td>
              <td><strong class="h3" id="invoice-total"><%= invoice_total(@sale) %></strong></td>
            </tr>
        </tbody>
      </table>
  </div>
</div>

Sayfamızın son hali şöyle oldu,



Başlığın yanındaki "+" butonuna tıklanınca http://localhost:3000/invoice_lines/new?sale_id=1 gibi bir parametre ile fatura satırı ekleme sayfasına gider. invoice_lines kontrolörü henüz yeni satır eklerken sale_id=1 gibi parametreyi anlayamadığı için form boş gelecektir. Formun bu fatura seçili olarak gelmesi için kontrolörün new metoduna şu ilaveyi yapalım,

app/controllers/invoice_lines_controller.rb
...
  # GET /invoice_lines/new
  def new
    @invoice_line = InvoiceLine.new
    if !params[:sale_id].nil?
      @invoice_line.sale = Sale.find(params[:sale_id])
    end
  end
...

Artık fatura ayrıntısından direk olarak yeni satır ilave edebileceğiz. Yeni satır eklendikten sonra tekrar fatura ayrıntı sayfasına dönmesini sağlamak için şimdilik bişey yapmayalım çünkü ilerde bazı karışıklıklara sebep olabilir. 




Aynı "+" butonu aktivitesini proje ayrıntısı sayfasından yeni fatura eklemek içinde yapmamız gerekiyor. 

app/controllers/sales_controller.rb
...
  def new
    @sale = Sale.new
    if !params[:project_id].nil?
      @sale.project = Project.find(params[:project_id])
    end
  end
...





Ödemeler Tablosu

Sıra geldi faturalara karşılık yapılan ödemelerin kayıt altına alındığı payments tablosuna. Konsolda tabloyu oluşturarak başlayalım.
rails g scaffold Payment sale:belongs_to note:string date:date value:float
rails db:migrate

Tarayıcımzda http://localhost:3000/payments sayfasına gidince ödeme kayıtları tablosu gelecektir. index sayfasından başlayalım,

app/views/payments/index.html.erb
<p id="notice"><%= notice %></p>

<div class="row">
  <div class="col-sm-4"><h1>Ödemeler</h1></div>
  <div class="col-sm"><%= link_to 'Yeni Ödeme', new_payment_path, class: "btn btn-primary", style: "margin: 20px;" %></div>
</div>

<div class="row">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Satış Faturası</th>
        <th>Not</th>
        <th>Tarih</th>
        <th>Değer</th>
        <th colspan="2"></th>
      </tr>
    </thead>

    <tbody>
      <% @payments.each do |payment| %>
        <tr>
          <td><%= link_to payment.sale.name, payment.sale %></td>
          <td><%= link_to payment.note, payment %></td>
          <td><%= payment.date %></td>
          <td><%= payment.value %></td>
          <td><%= link_to 'Düzenle', edit_payment_path(payment), class: "btn btn-primary" %></td>
          <td><%= link_to 'Sil', payment, method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-danger" %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>

<br>



Ardından new , edit , _form düzenlemeleri,

app/views/payments/new.html.erb
<h1>Yeni Ödeme</h1>

<%= render 'form', payment: @payment, etiket: "Ekle" %>
<div class="row"></div>
<%= link_to 'Geri', payments_path, class:"btn btn-primary" %>


app/views/payments/edit.html.erb
<h1>Ödeme Düzenleme</h1>

<%= render 'form', payment: @payment, etiket: "Kaydet" %>

<div class="row"></div>
<%= link_to 'Göster', @payment, class: "btn btn-primary" %> |
<%= link_to 'Liste', payments_path, class: "btn btn-info" %>

ve form

app/views/payments/_form.html.erb
<%= form_with(model: payment, local: true) do |form| %>
...
...
  <div class="form-group col-sm-8">
    <%= form.label "Firması :" %>
    <%= form.collection_select("company_id", Company.all, :id, :name, 
      {:include_blank => true, 
        selected: @payment.sale.nil? ? nil : @payment.sale.project.company_id}, 
      { class: "form-control", id: "company-select" }) %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Projesi :" %>
    <%= form.collection_select("project_id", @payment.sale.nil? ? Project.all : Project.where(company_id: @payment.sale.project.company_id), :id, :name, 
      { include_blank: true, 
        selected: @payment.sale.nil? ? nil : @payment.sale.project_id }, 
      { class: "form-control", id: "project-select" }) %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Satış Faturası :" %>
    <%= form.collection_select(:sale_id,  @payment.sale.nil? ? Sale.all : Sale.where(project_id: @payment.sale.project_id), :id, :name, 
      { include_blank: true,
        selected: @payment.sale.nil? ? nil : @payment.sale.id }, 
      { class: "form-control", id: "sale-select" }) %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Not :" %>
    <%= form.text_field :note, id: :payment_note, class: "form-control" %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Tarih :" %>
    <%= form.date_select :date, id: :payment_date, class: "form-control" %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Ödenen Miktar :" %>
    <%= form.text_field :value, id: :payment_value, class: "form-control" %>
  </div>

  <div class="actions form-group col-sm-8">
    <%= form.submit etiket, class: "btn btn-success" %>
  </div>
<% end %>


<%= javascript_tag do %>
  $("#company-select").change(function(){
    if(this.value){
      $.ajax({url: "/companies/getProjects?id=" + this.value, success: function(result){
        var project_select = $("#project-select");
        project_select.empty();
        $.each(result, function(index, value){
          var opt = $("<option/>");
          opt.attr("value", value[0]);
          opt.text(value[1]);
          opt.appendTo(project_select);
        });
        $("<option/>").attr("selected", "selected").attr("value", 0).text("").prependTo(project_select);
      }});
    };
  });

  $("#project-select").change(function(){
    if(this.value){
      $.ajax({url: "/projects/getSales?id=" + this.value, success: function(result){
        var sale_select = $("#sale-select");
        sale_select.empty();
        $.each(result, function(index, value){
          var opt = $("<option/>");
          opt.attr("value", value[0]);
          opt.text(value[1]);
          opt.appendTo(sale_select);
        });
        $("<option/>").attr("selected", "selected").attr("value", 0).text("").prependTo(sale_select);
      }});
    };
  });
<% end %>

Sırada ayrıntı sayfası var,

app/views/payments/show.html.erb
<p id="notice"><%= notice %></p>

<div class="row">
  <div class="col-sm-12">
    <p>
      <strong class="col-sm-3">Satış Faturası :</strong>
      <%= link_to @payment.sale.name, @payment.sale %>
    </p>

    <p>
      <strong class="col-sm-3">Not :</strong>
      <%= @payment.note %>
    </p>

    <p>
      <strong class="col-sm-3">Tarih :</strong>
      <%= @payment.date %>
    </p>

    <p>
      <strong class="col-sm-3">Ödenen :</strong>
      <%= @payment.value %>
    </p>
  </div>
</div>

<%= link_to 'Düzenle', edit_payment_path(@payment), class: "btn btn-primary" %> |
<%= link_to 'Liste', payments_path, class: "btn btn-info" %>

Ayrıntılara pek girmedim , fatura satırlarında ne yaptıysak aynı şeyleri bu tabloda da yaptık.



Fatura Ayrıntısına Ödemeler Listesi Eki

Dalmadan has_many ilavemizi yapalım,

app/models/sale.rb
class Sale < ApplicationRecord
  belongs_to :project
  has_many :invoice_lines
  has_many :payments
end

Fatura satırlarını eklediğimiz gibi bu faturaya karşılık aldığımız ödemeleri de fatura ayrıntı sayfasına ekleyelim. 

app/views/sales/show.html.erb
...
<div class="row">
  <div class="col-sm-12">
    <strong class="h3">Ödemeler</strong>
    <%= link_to '+', new_payment_path + "?sale_id=" + @sale.id.to_s, class: "btn btn-success", style: "margin: 20px;" %>
  </div>
  <div class="col-sm"></div>
    <hr/>
  <div class="col-sm-12">
      <table class="table table-striped">
        <thead>
          <tr>
            <th>Not</th>
            <th>Tarih</th>
            <th>Değer</th>
            <th colspan="2"></th>
          </tr>
        </thead>

        <tbody>
          <% @sale.payments.each do |payment| %>
            <tr>
              <td><%= link_to payment.note, payment %></td>
              <td><%= payment.date %></td>
              <td><%= payment.value %></td>
              <td><%= link_to 'Düzenle', edit_payment_path(payment), class: "btn btn-primary" %></td>
              <td><%= link_to 'Sil', payment, method: :delete, data: { confirm: payment.note + ' satırı silinecek emin misin?' }, class: "btn btn-danger" %></td>          
            </tr>
          <% end %>
            <tr>
              <td colspan="1"></td>
              <td><strong>Ödemeler<br> Toplamı :</strong></td>
              <td><strong class="h3" id="payment-total"><%= payment_total(@sale) %></strong></td>
            </tr>
        </tbody>
      </table>
  </div>
</div>

Burada faturaya ait ödemeler toplamını hesaplayan payment_total metodunu helper dosyası içine ekleyerek devam edelim.

app/helpers/sales_helper.rb
...
  def payment_total(sale)
    total = 0
    sale.payments.each do |payment|
        total += payment.value
    end
    "%.2f" % total
  end

Fatura ayrıntı sayfamızın görünüşü şöyle oldu,



Ödemeler bağlığı yanıdaki  "+" butonu tıklanınca bu faturanın seçili olarak gelmesi için aynı fatura satırı eklerken olduğu gibi, yeni ödeme metodunda da değişiklik yapıyoruz.

app/controllers/payments_controller.rb
...
  # GET /payments/new
  def new
    @payment = Payment.new
    if !params[:sale_id].nil?
      @payment.sale = Sale.find(params[:sale_id])
    end
  end
...

Bu fatura ayrıntı sayfasına kesilen fatura, alınan ödemeler şöyle bir hesap yapıp net alacağımızı da şöyle kocaman yazalım. Hatırlarsak yukarıda sağ üst tarafta 2 sütunluk bir boş yer bırakmıştık oraya şu ilave görseli ekleyelim.

app/views/sales/show.html.erb
...
  </div>
  <div class="col-sm-2">
    <h3>Net Alacak</h3>
    <h3 id="net-total" class="text-center">YOK</h3>
  </div>
</div>

<%= link_to 'Düzenle', edit_sale_path(@sale), class: "btn btn-primary" %> |
...

Bu ilave fatura ayrıntı sayfasında sağ üst köşeye büyük puntolarla Net Alacak ve altına da YOK yazacaktır. Şimdi o YOK yazısının yerine toplam alacağımızı hesaplayan bir JavaScript kodu ekleyelim en alta.

app/views/sales/show.html.erb
...
<%= javascript_tag do %>
  $(function(){
    var netTotal = $("#invoice-total").text() - $("#payment-total").text();
    $("#net-total").text(netTotal.toFixed(2));
    if(netTotal > 1.0)
      $("#net-total").css("background-color", "pink");
    else $("#net-total").css("background-color", "lime");
  });
<% end %>
...

Zaten sayfada olan fatura toplamı ve ödemeler toplamı miktarlarından net alacağımızı hesaplayıp yerine yazdık. Yetmedi değerin arkasını alacağımız varsa kırmızı yoksa yeşil yaparak renklendirme de ekledik. Niye değer 1.0'dan büyük mü diye sorduk? Çünkü float değişkenler kullandık ve kuruşluk hatalar işlem hassasiyeti sonucu olabilir. Aslında muhasebe hesapları yapılırken float kullanılmaz, ama biz de bunları devlete beyanname diye vermeyeceğiz, kuruşluk hatalar olsun ne olacak. Alacağımız 1 liranın altındaysa o da varsın helal olsun. O saçma ayrıntılarda kaybolmayalım şimdi.

Görüntü şuna benzeyecek,







Alacakların Diğer Sayfalarda Gösterimi

Satışlar index sayfasında fatura toplamı ve kalan alacak değerini gösteren 2 sütun ilave edelim. 

app/views/sales/index.html.erb
...

<div class="row">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Proje</th>
        <th>İsim</th>
        <th>Satış Tarihi</th>
        <th>Ödeme Tarihi</th>
        <th>Toplam</th>
        <th>Alacak</th>
        <th colspan="2"></th>
      </tr>
    </thead>

    <tbody>
      <% @sales.each do |sale| %>
        <tr>
          <td><%= link_to sale.project.name, sale.project %></td>
          <td><%= link_to sale.name, sale %></td>
          <td><%= sale.salesDate %></td>
          <td><%= sale.paymentDate %></td>
          <td><%= invoice_total(sale) %></td>
          <% net_total = invoice_total(sale).to_f - payment_total(sale).to_f %>
          <td class="h4" style="color:<% if (net_total > 1) %>red<% else %>blue<% end %>"><%= net_total %></td>
          <td><%= link_to 'Düzenle', edit_sale_path(sale), class: "btn btn-primary" %></td>
          <td><%= link_to 'Sil', sale, method: :delete, data: { confirm: sale.name + ' faturası silinecek emin misin?' }, class: "btn btn-danger" %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>

<br>

Bi yerden yalış girdik, şimdi ızdırap oluyor. Metodlardan geriye yazı döndürdük , ama şimdi onları değer olarak kullanmak gerekince to_f eklemek zorunda kalıyoruz. Neyse , gençsiniz , siz düzeltirsiniz. http://localhost:3000/sales sayfamız şöyle görünüyor artık.



Burada da yazıları renklendirdik, hesapları ve renklendirmeleri bu sefer ruby-erb kullanarak yaptık. 

Proje ayrıntı sayfasında da faturalar listesine alacak sütunu ekleyelim.

app/views/projects/show.html.erb
...
  <div class="col-sm-8">
    <strong class="h3">Satış Faturaları</strong>
    <%= link_to '+', new_sale_path + "?project_id=" + @project.id.to_s, class: "btn btn-success", style: "margin: 20px;" %>
      <table class="table table-striped">
        <thead>
          <tr>
            <th>İsim</th>
            <th>Satış Tarihi</th>
            <th>Ödeme Tarihi</th>
            <th>Toplam</th>
            <th>Alacak</th>
          </tr>
        </thead>

        <tbody>
          <% @project.sales.each do |sale| %>
            <tr>
              <td><%= link_to sale.name, sale %></td>
              <td><%= sale.salesDate %></td>
              <td><%= sale.paymentDate %></td>
              <td><%= invoice_total(sale) %></td>
              <% net = invoice_total(sale).to_f - payment_total(sale).to_f %>
              <td style="color: <%= net > 1 ? 'red' : 'blue' %>;"><%= "%.2f" % net %></td>
            </tr>
          <% end %>
        </tbody>
      </table>
  </div>
...

Yaptığımız ilave sonucu proje ayrıntı sayfası şöyle görünecektir.



Şu ana kadar ana arterlerden birini tamamladık. Artık projelere kestiğimiz faturaları ve müşterinin bize yaptığı ödemeleri kayıt altına aldık. Ama alacağımıza aslan borcumuza kedi olmayalım. Projeler için yaptığımız masrafları da kayıt altına alalım.


Alımlar Tablosu

Aslında yaptığımız mal ve hizmet alımlarını da fatura olarak sales tablosunda kaydedebiliriz. Ama böyle yaparsak her faturanın satış mı yoksa alım mı olduğunu belirtmek , alacak ve borç hesaplarken aynı tablo üzerinde daha karmaşık işlemler yapmak zorunda kalacağız. Ben, basit kalmaktan taraf olduğumdan alımlar için satışlar ile aynı yapıda bir tablo daha oluşturdum. 

Konsolda tablomuzu oluşturalım,

rails g scaffold Purchase project:belongs_to name:string salesDate:date paymentDate:date
rails db:migrate

Hiç başımıza sorun gelmeden Proje modeline has_many ilavemizi yapalım.

app/models/project.rb
class Project < ApplicationRecord
  belongs_to :company
  has_many :project_people
  has_many :sales
  has_many :purchases
end

Ana menüye Alımlar link butonunu da ekleyelim. 

app/layouts/application.html.erb
...
  <nav class="navbar navbar-default">
    <a href="http://www.turkpoem.com" class="navbar-brand" target="_blank">POEM</a>
    <a href="/companies" class="btn btn-success">Firmalar</a>
    <a href="/people" class="btn btn-success">Kişiler</a>
    <a href="/projects" class="btn btn-success">Projeler</a>
    <a href="/sales" class="btn btn-success">Satışlar</a>
    <a href="/purchases" class="btn btn-success">Alımlar</a>
  </nav>
...

index sayfasından başlayalım düzenlemeye

app/views/purchases/index.html.erb
<p id="notice"><%= notice %></p>

<div class="row">
  <div class="col-sm-4"><h1>Alımlar</h1></div>
  <div class="col-sm"><%= link_to 'Yeni Alım Faturası', new_purchase_path, class: "btn btn-primary", style: "margin: 20px;" %></div>
</div>

<div class="row">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Proje</th>
        <th>İsim</th>
        <th>Alım Tarihi</th>
        <th>Ödeme Tarihi</th>
        <th colspan="2"></th>
      </tr>
    </thead>

    <tbody>
      <% @purchases.each do |purchase| %>
        <tr>
          <td><%= link_to purchase.project.name, purchase.project %></td>
          <td><%= link_to purchase.name, purchase %></td>
          <td><%= purchase.salesDate %></td>
          <td><%= purchase.paymentDate %></td>
          <td><%= link_to 'Düzenle', edit_purchase_path(purchase), class: "btn btn-primary" %></td>
          <td><%= link_to 'Sil', purchase, method: :delete, data: { confirm: purchase.name + ' faturası silinecek emin misin?' }, class: "btn btn-danger" %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>

<br>

new , edit ve form düzenlemeleri var sırada. Daha önce satışlarda aynılarını yaptık, o yüzden hızlı hızlı geçiyoruz.

app/views/purchases/new.html.erb
<h1>Yeni Alım Faturası</h1>

<%= render 'form', purchase: @purchase, etiket: "Ekle" %>
<div class="row"></div>
<%= link_to 'Geri', purchases_path, class:"btn btn-primary" %>


app/views/purchases/edit.html.erb
<h1>Alım Faturası Düzenleme</h1>

<%= render 'form', purchase: @purchase, etiket: "Kaydet" %>

<div class="row"></div>
<%= link_to 'Göster', @purchase, class: "btn btn-primary" %> |
<%= link_to 'Liste', purchases_path, class: "btn btn-info" %>

ve form

app/views/purchases/_form.html.erb
...
  <div class="form-group col-sm-8">
    <%= form.label "Firması :" %>
    <%= form.collection_select("company_id", Company.all, :id, :name, 
      {:include_blank => true, 
        selected: @purchase.project.nil? ? nil : @purchase.project.company.id}, 
      { class: "form-control", id: "company-select" }) %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Projesi :" %>
    <%= form.collection_select(:project_id, @purchase.project.nil? ? Project.all : Project.where(company_id: @purchase.project.company_id), :id, :name, 
      { include_blank: true }, 
      { class: "form-control", id: "project-select" }) %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "İsim :" %>
    <%= form.text_field :name, id: :purchase_name, class: "form-control" %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Fatura Tarihi :" %>
    <%= form.date_select :salesDate, id: :purchase_salesDate, 
        :start_year => 2016, 
        :end_year => 2030 %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Ödeme Tarihi" %>
    <%= form.date_select :paymentDate, id: :purchase_paymentDate, 
        :start_year => 2016, 
        :end_year => 2030 %>
  </div>

  <div class="actions form-group col-sm-8">
    <%= form.submit etiket, class: "btn btn-success" %>
  </div>
<% end %>

<%= javascript_tag do %>
  $("#company-select").change(function(){
    $.ajax({url: "/companies/getProjects?id=" + this.value, success: function(result){
      var project_select = $("#project-select");
      project_select.empty();
      $.each(result, function(index, value){
        var opt = $("<option/>");
        opt.attr("value", value[0]);
        opt.text(value[1]);
        opt.appendTo(project_select);
      });
      $("<option/>").attr("selected", "selected").attr("value", 0).text("").prependTo(project_select);
    }});
  });
<% end %>



app/views/purchases/show.html.erb
<p id="notice"><%= notice %></p>

<div class="row">
  <div class="col-sm-10">
	<p>
      <strong class="col-sm-2">Projesi :</strong>
      <%= link_to @purchase.project.name, @purchase.project %>
	</p>

	<p>
      <strong class="col-sm-2">İsmi :</strong>
	  <%= @purchase.name %>
	</p>

	<p>
      <strong class="col-sm-2">Fatura Tarihi ::</strong>
	  <%= @purchase.salesDate %>
	</p>

	<p>
      <strong class="col-sm-2">Ödeme Tarihi :</strong>
	  <%= @purchase.paymentDate %>
	</p>
  </div>
  <div class="col-sm-2">
  </div>
</div>


<%= link_to 'Düzenle', edit_purchase_path(@purchase), class: "btn btn-primary" %> |
<%= link_to 'Liste', purchases_path, class: "btn btn-info" %>

<hr/>

Birkaç örnek fatura girişi yaptıktan sonra listemiz şöyle görünecek.






Fatura Satırlarına Alım Faturalarının Eklenmesi

Sıra geldi yukarıda tükürdüğümü burada yalamaya. invoice_lines tablosunu alım faturalarının satırlarını işlemek için de kullanacağız. Bir yandan iyi oldu, mevcut tabloya nasıl sütun ilavesi yapılacak bunu da görmüş oluruz. Fatura satırlarını alım faturalarına da bağlamak için konsolda,

rails g migration AddPurchaseToInvoiceLines purchase:belongs_to
rails db:migrate

Bu komutlar invoice_lines tablosuna purchase_id adında bir sütun ekleyerek alım faturaları ile bağlantı kuracaktır. invoice_lines:index sayfasına alım faturasını da ekleyerek başlayalım,

app/views/invoice_lines/index.html.erb
...
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Kodu</th>
        <th>Satış Faturası</th>
        <th>Alım Faturası</th>
 ...
    <tbody>
      <% @invoice_lines.each do |invoice_line| %>
        <tr>
          <td><%= invoice_line.kod %></td>
          <td>
            <%= invoice_line.sale_id.nil? ? "..." :
              (link_to invoice_line.sale.name, invoice_line.sale) %></td>
          <td>
            <%= invoice_line.purchase_id.nil? ? "..." : 
              (link_to invoice_line.purchase.name, invoice_line.purchase) %></td>
...

Önce Alım Faturası başlığını tablo bağlıklarına ekliyoruz. Sonra satış faturasına bağlıysa onu , yok alım faturasına bağlıysa onu link olarak ilgili sütuna yazıyoruz. Olmayan yerine de "..." yazıp olmadığını belirtiyoruz. 

Devam edelim. purchases:show görseline en alta fatura satırlarını ekleyelim. 

app/views/purchases/show.html.erb
...
<div class="row">
  <div class="col-sm-12">
    <strong class="h3">Fatura Satırları</strong>
    <%= link_to '+', new_invoice_line_path + "?purchase_id=" + @purchase.id.to_s, class: "btn btn-success", style: "margin: 20px;" %>
  </div>
  <div class="col-sm-12">
      <table class="table table-striped">
        <thead>
          <tr>
            <th>Kod</th>
            <th>Ürün</th>
            <th>Fiyat</th>
            <th>Miktar</th>
            <th>Birim</th>
            <th>KDV</th>
            <th>Toplam</th>
            <th colspan="2"></th>
          </tr>
        </thead>

        <tbody>
          <% @purchase.invoice_lines.each do |invoice_line| %>
            <tr>
              <td><%= invoice_line.kod %></td>
              <td><%= link_to invoice_line.product, invoice_line %></td>
              <td><%= invoice_line.unitPrice %></td>
              <td><%= invoice_line.qty %></td>
              <td><%= invoice_line.unit.name %></td>
              <td><%= invoice_line.tax.name + "-%.2f" % (invoice_line.tax.value * 
              invoice_line.qty * invoice_line.unitPrice) %></td>              
              <td>
                <% total = (invoice_line.tax.value + 1) * invoice_line.qty * invoice_line.unitPrice %>
                <%= "%.2f" % (total) %>
              </td>    
              <td><%= link_to 'Düzenle', edit_invoice_line_path(invoice_line), class: "btn btn-primary" %></td>
              <td><%= link_to 'Sil', invoice_line, method: :delete, data: { confirm: invoice_line.product + ' satırı silinecek emin misin?' }, class: "btn btn-danger" %></td>          
            </tr>
          <% end %>
            <tr>
              <td colspan="5"></td>
              <td><strong>Fatura<br> Toplamı :</strong></td>
              <td><strong class="h3" id="invoice-total"><%= purchase_total(@purchase) %></strong></td>
            </tr>
        </tbody>
      </table>
  </div>
</div>

Tabi alım faturalarından herhangi birinin ismini tıkladığımızda ayrıntı sayfası  @purchase.invoice_lines metodunda hata verecek. Yine has_many unuttuk. purchase modelini değiştirelim. 

app/models/purchase.rb
class Purchase < ApplicationRecord
  belongs_to :project
  has_many :invoice_lines
end

Bir de helper metodları eklememiz lazım. Onları da satış faturalarına bakarak yeni isimlerle oluşturalım.

app/helpers/purchases_helper.rb
module PurchasesHelper
    def purchase_total(purchase)
        total = 0
        purchase.invoice_lines.each do |line|
            total += (line.tax.value + 1) * line.qty * line.unitPrice
        end
        "%.2f" % total
    end
end

Sonunda görsel hatasız çalışmaya başladı. 



Ben burada hangi sırayla gittim bilmiyorum ama yukarıda bir şey kaçtı yine. Daha önceden olan tabloya belongs_to sütun ekledik ya, işte tablo daha önceden tanımlanmış olduğu için modele ilaveyi manual yapmamız gerekiyor. 

app/models/invoice_line.rb
class InvoiceLine < ApplicationRecord
  belongs_to :sale
  belongs_to :purchase
  belongs_to :unit
  belongs_to :tax
end

Sırada neredeyse bu uygulamanın en çorba sayfalarından biri var. Yeni fatura satırı girilen invoice_lines:_form görselinde alım faturaları için de bir dropdown ekleyeceğiz. Eklemek yetmez kayıt satış faturasına bağlıysa onun bilgileri , alım faturasına bağlıysa onun bilgileri gelecek. Yani daha önce olan kısımlar da değişecek. 

Adım adım gitsek daha iyi. Örnek bir alım faturası ayrıntı sayfasında Fatura Satırları başlığı yanındaki "+" butonuna tıklayarak yeni fatura satırı formunu açalım. Gördüğümüz gibi firma adı ve projesi gelmedi. Bunun ilk sebebi http://localhost:3000/invoice_lines/new?purchase_id=1 şeklinde bir adres verdik, ama parametre olarak verdiğimiz purchase_id=1 kontrolör içinde değerlendirilmiyor. Kontrolör içinde new metodunu düzenleyelim.

app/controllers/invoice_lines_controller.rb
...
  def new
    @invoice_line = InvoiceLine.new
    if !params[:sale_id].nil?
      @invoice_line.sale = Sale.find(params[:sale_id])
    elsif !params[:purchase_id].nil?
      @invoice_line.purchase = Purchase.find(params[:purchase_id])
    end
  end
...

Daha önce sale_id parametresi var mı diye bakıyordu, şimdi o yoksa purchase_id verilmişse onu alarak formu açmaya başladı. Şimdi forma dalalım sıra sıra. Firma seçiminde eğer alım faturası varsa onun bağlı olduğu firmayı seçili getirmek için,

app/views/invoice_lines/_form.html.erb
...
  <div class="form-group col-sm-8">
    <%= form.label "Firması :" %>
    <%= form.collection_select("company_id", Company.all, :id, :name, 
      {:include_blank => true, 
        selected: @invoice_line.sale.nil? ? 
          (@invoice_line.purchase.nil? ? nil : 
            @invoice_line.purchase.project.company_id) : 
          @invoice_line.sale.project.company_id}, 
      { class: "form-control", id: "company-select" }) %>
  </div>
...

Önceden sadece satış faturası var mı diye bakıyorduk. Şimdi satış faturası yoksa acaba alım faturası var mı diye de bakıyoruz. Şimdi sayfayı yenilersek firmanın seçili geldiğini görürüz,



Projelerin listesiyle devam ediyoruz,

app/views/invoice_lines/_form.html.erb
...
  <div class="form-group col-sm-8">
    <%= form.label "Projesi :" %>
    <%= form.collection_select("project_id", @invoice_line.sale.nil? ? 
      (@invoice_line.purchase.nil? ? Project.all : Project.where(company_id: @invoice_line.purchase.project.company_id)) : 
      Project.where(company_id: @invoice_line.sale.project.company_id), :id, :name, 
      { include_blank: true, 
        selected: @invoice_line.sale.nil? ? 
          (@invoice_line.purchase.nil? ? nil :
            @invoice_line.purchase.project_id) : 
          @invoice_line.sale.project_id }, 
      { class: "form-control", id: "project-select" }) %>
  </div>
...

Önce listeye getirirken satış faturasına bağlıysa onun firmasının projeleri, yok alım faturasına bağlıysa onun firmasının projeleri her ikisi de yoksa tüm projeler gelecek. Sonra seçili olan da satış ya da alım faturası bağlantısına göre seçilecek. 



Gereği var mı bilmem ama satış faturaları listesine de seçenek olarak sadece alım faturasının bağlı olduğu projenin satış faturalarını getirelim.

app/views/invoice_lines/_form.html.erb
...
  <div class="form-group col-sm-6">
    <%= form.label "Satış Faturası :" %>
    <%= form.collection_select(:sale_id, @invoice_line.sale.nil? ? 
      (@invoice_line.purchase.nil? ? Sale.all : Sale.where(project_id: @invoice_line.purchase.project_id)) : 
      Sale.where(project_id: @invoice_line.sale.project_id), :id, :name, 
      { include_blank: true,
        selected: @invoice_line.sale.nil? ? nil : @invoice_line.sale.id }, 
      { class: "form-control", id: "sale-select" }) %>
  </div>
...

Alım faturaları seçim listesi forma yeni eklenecek. Onu da satış faturaları seçimine benzer bir kodla yapıyoruz.

app/views/invoice_lines/_form.html.erb
...
  <div class="form-group col-sm-6">
    <%= form.label "Alım Faturası :" %>
    <%= form.collection_select(:purchase_id, @invoice_line.purchase.nil? ? 
      (@invoice_line.sale.nil? ? Purchase.all : Purchase.where(project_id: @invoice_line.sale.project_id)) : 
      Purchase.where(project_id: @invoice_line.purchase.project_id), :id, :name, 
      { include_blank: true,
        selected: @invoice_line.purchase.nil? ? nil : @invoice_line.purchase.id }, 
      { class: "form-control", id: "purchase-select" }) %>
  </div>
...

Formun şekli tamamlandı son görünüm şöyle olacak.



Formu açarken yapılacaklar tamam da bir de form da firma ve proje seçerek ilerlendiğinde listeleri değiştiren JavaScript kodlarımız vardı aşağıda. Orada da proje seçilince alım faturaları listesine o projeye ait alım faturaları gelmesi için ilave yapmalıyız. 

app/views/invoice_lines/_form.html.erb
...
  $("#project-select").change(function(){
    if(this.value){
      $.ajax({url: "/projects/getSales?id=" + this.value, success: function(result){
        var sale_select = $("#sale-select");
        sale_select.empty();
        $.each(result, function(index, value){
          var opt = $("<option/>");
          opt.attr("value", value[0]);
          opt.text(value[1]);
          opt.appendTo(sale_select);
        });
        $("<option/>").attr("selected", "selected").attr("value", 0).text("").prependTo(sale_select);
      }});

      $.ajax({url: "/projects/getPurchases?id=" + this.value, success: function(result){
        var purchase_select = $("#purchase-select");
        purchase_select.empty();
        $.each(result, function(index, value){
          var opt = $("<option/>");
          opt.attr("value", value[0]);
          opt.text(value[1]);
          opt.appendTo(purchase_select);
        });
        $("<option/>").attr("selected", "selected").attr("value", 0).text("").prependTo(purchase_select);
      }});

    };
  });
...

Ajax çağrısının yapıldığı projects/getPurchases metodunu kontrolör içine ekleyip route ilavesini de yapmalıyız.

app/controllers/projects_controller.rb
...
  def getPurchases
    render json: Project.find(params["id"]).purchases.map{|p| [p.id, p.name]}
  end

  private
...


config/routes.rb
...
  resources :projects do
    collection do
      post "addPerson"
      get "destroyPerson"
      get "getSales"
      get "getPurchases"
    end
  end
...

Artık proje değiştirince o projeye ait alım faturalarının da listeye otomatik gelmesini sağladık. 

Her şey hazır hadi alım faturasına bir kaç satır ekleyim dedim ama ilaveyi yapmadı ve bir hata mesajı verdi.



Birincisi satış faturası ille de girilmeli diyor. İkincisi alım faturası da girilmeli diyor. Bu ikinciye gıcık oldum, alım faturası seçili niye yokmuş gibi mesaj verdi? 

invoice_lines_controller.rb kontrolörünün en sonunda yeni kayıt girerken ya da kayıt düzenlerken girilebilecek verileri kısıtlayan invoice_line_params metodu var,

app/controllers/invoice_lines_controller.rb
...
    # Only allow a list of trusted parameters through.
    def invoice_line_params
      params.require(:invoice_line).permit(:sale_id, :kod, :product, :unitPrice, :qty, :unit_id, :tax_id)
    end
end

İşte bu metodda :purchase_id belirtilmediği için benim formdan gönderdiğim purchase_id değerini kesip atıyor, sonra da bu niye yok diye bana soruyor. İlave edelim de değeri makaslamasın.

app/controllers/invoice_lines_controller.rb
...
    def invoice_line_params
      params.require(:invoice_line).permit(:sale_id, :purchase_id, :kod, :product, :unitPrice, :qty, :unit_id, :tax_id)
    end
end

Şimdi yeni satır girmeye kalkınca hata 1 tane kaldı sadece satış faturası istiyor. Ben Rails versiyon 5 kullanıyorum ve bu versiyon ile beraber belongs_to ile belirtilen bağlantılara veri girme mecburiyeti getirilmiş. Benim buraya veri girilmesine gerek olmadığını belirten bir ilave yapmam gerekiyor. Modeli açalım ve 2 belongs_to satırını değiştirelim.

app/models/invoice_line.rb
class InvoiceLine < ApplicationRecord
  belongs_to :sale, optional: true
  belongs_to :purchase, optional: true
  belongs_to :unit
  belongs_to :tax
end

Bu modifikasyonla bu iki sütun verisinin opsiyonel olduğunu istersek vermeyebileceğimizi belirttik. Artık ikisi de verilmezse ne olur , her ikisi de verilirse ne olur bilemem. Merak eden kurcalasın. Değer girmeyi başarınca faturaya geri dönecek yer bulamadık. Çünkü fatura satırı ayrıntı ekranında alım faturasını eklememişiz. 


app/views/invoice_lines/show.html.erb
...
      <strong class="col-sm-3">Satış Faturası :</strong>
      <%= @invoice_line.sale.nil? ? "..." : (link_to @invoice_line.sale.name, @invoice_line.sale) %>
    </p>

    <p>
      <strong class="col-sm-3">Alım Faturası :</strong>
      <%= @invoice_line.purchase.nil? ? "..." : (link_to @invoice_line.purchase.name, @invoice_line.purchase) %>
    </p>
...

Bir iki satır girdikten sonra alım faturası sayfamız şuna benzeyecek



Fatura satırlarını girerken bir şey farkettim. Satış faturasına satır girerken bizim sattığımız mal olduğu için net fiyatı ve kdv değerini ayrı ayrı biliyoruz. Ama alım faturaları ve özellikler benzin yemek gibi satırları girerken kdv dahil bir fiş alıyoruz. Toplam değerden geri dönen bir aksiyon tanımı yapsak iyi olacak. 

Bu alternetif hesaplama için javascript kullanacağız. Formun dışında kalacak şekilde arkasına şunları ekleyelim. 

app/views/invoice_lines/_form.html.erb
...
 <% end %>

<div class="col-sm-2">
  <input type="text" name="" id="line-total" class="form-control">
</div>

<div class="col-sm-2">
  <button id="line-button" class="btn btn-primary">Hesapla</button>
</div>

<p id="taxes" style="display: none;"><%= Tax.all.map{ |t| t.value }.join(",") %></p>
...

Burada sağ alta 2 tane görsel ekliyoruz. KDV değeri elimizde id olarak bulunduğu için karşılık gelen değerleri de virgül ile ayrılmış bir string olarak ve görünmez olarak sayfaya ekliyoruz. 

Hesapla butonu tıklanınca yanındaki toplama girilen değeri alarak verilen miktar ve kdv değerlerinden hesapla fiyatı oluşturmak için JavaScript kodumuza ilave yapıyoruz. 


app/views/invoice_lines/_form.html.erb
...
  $("#line-button").click(function(){
    var line_total = $("#line-total").val();
    var i_l_qty = $("#invoice_line_qty").val();
    var i_l_tax = parseFloat($("#taxes").text().split(",")[$("#invoice_line_tax").val()-1]);
    $("#invoice_line_unitPrice").val((line_total / (1 + i_l_tax) / i_l_qty).toFixed(2));
  });
...

Artık 100 liralık kdv dahil benzin aldığımızda toplamdan geri hesap yoluyla fiyatı oluşturabiliriz.






Proje Ayrıntısına Alım Faturaları İlavesi

Proje ayrıntı sayfasında satış faturalarını liste halinde eklemiştik. Projenin takibi için alım faturalarını da sayfaya ekleyelim.

app/views/projects/show.html.erb
...
<div class="row">
  <div class="col-sm-4"></div>
  <div class="col-sm-8">
    <strong class="h3">Alım Faturaları</strong>
    <%= link_to '+', new_purchase_path + "?project_id=" + @project.id.to_s, class: "btn btn-success", style: "margin: 20px;" %>
      <table class="table table-striped">
        <thead>
          <tr>
            <th>İsim</th>
            <th>Alım Tarihi</th>
            <th>Ödeme Tarihi</th>
            <th>Toplam</th>
          </tr>
        </thead>

        <tbody>
          <% @project.purchases.each do |purchase| %>
            <tr>
              <td><%= link_to purchase.name, purchase %></td>
              <td><%= purchase.salesDate %></td>
              <td><%= purchase.paymentDate %></td>
              <td><%= purchase_total(purchase) %></td>
            </tr>
          <% end %>
        </tbody>
      </table>
  </div>
</div>

Alım faturalarının listesi de proje ayrıntı sayfasına eklendi.






Ödemeler Tablosuna Alım Faturaları Eklenmesi

Eh yukarıda bayağı öğrendik. Şimdi benzer şekilde ödemeler tablosuna da alım faturalarına bağlantı için bir sütun ekleyelim. Konsolda tablo modifikasyonunu yaparak başlayalım,

rails g migration AddPurchaseToPayments purchase:belongs_to
rails db:migrate

Ne güzel İstanbul be, Rails herşeyi yapıyor, biz işçiliklerle değil odaklanmamız gereken yerlerde çalışıyoruz. 

http://localhost:3000/payments sayfasına alım fatura bağlantısını da eklememiz gerekiyor.

app/views/payments/index.html.erb
...
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Satış Faturası</th>
        <th>Alım Faturası</th>
        <th>Not</th>
        <th>Tarih</th>
        <th>Değer</th>
        <th colspan="2"></th>
      </tr>
    </thead>

    <tbody>
      <% @payments.each do |payment| %>
        <tr>
          <td><%= payment.sale_id.nil? ? "..." :
              (link_to payment.sale.name, payment.sale) %></td>
          <td><%= payment.purchase_id.nil? ? "..." : 
            (link_to payment.purchase.name, payment.purchase) %></td>
          <td><%= link_to payment.note, payment %></td>
...

Sayfamız şu hale gelecektir,



Alım fatura ayrıntısına ödeme satırlarını da ekleyelim.

app/views/purchases/show.html.erb
...
 <div class="row">
  <div class="col-sm-12">
    <strong class="h3">Ödemeler</strong>
    <%= link_to '+', new_payment_path + "?purchase_id=" + @purchase.id.to_s, class: "btn btn-success", style: "margin: 20px;" %>
  </div>
  <div class="col-sm"></div>
    <hr/>
  <div class="col-sm-12">
      <table class="table table-striped">
        <thead>
          <tr>
            <th>Not</th>
            <th>Tarih</th>
            <th>Değer</th>
            <th colspan="2"></th>
          </tr>
        </thead>

        <tbody>
          <% @purchase.payments.each do |payment| %>
            <tr>
              <td><%= link_to payment.note, payment %></td>
              <td><%= payment.date %></td>
              <td><%= payment.value %></td>
              <td><%= link_to 'Düzenle', edit_payment_path(payment), class: "btn btn-primary" %></td>
              <td><%= link_to 'Sil', payment, method: :delete, data: { confirm: payment.note + ' satırı silinecek emin misin?' }, class: "btn btn-danger" %></td>          
            </tr>
          <% end %>
            <tr>
              <td colspan="1"></td>
              <td><strong>Ödemeler<br> Toplamı :</strong></td>
              <td><strong class="h3" id="payment-total">
                <%= purchase_payment_total(@purchase) %></strong></td>
            </tr>
        </tbody>
      </table>
  </div>
</div>

Burada kullanılan purchase_payment_total (ki payments olmalıydı) metodunu purchases_helper.rb içinde tanımlayalım.

app/helpers/purchases_helper.rb
...
    def purchase_payment_total(purchase)
        total = 0
        purchase.payments.each do |payment|
            total += payment.value
        end
        "%.2f" % total
    end
end

Haydaa, şimdi de purchase.payments ne demek diye sordu. Yine belongs_to, yine has_many

app/models/purchase.rb
class Purchase < ApplicationRecord
  belongs_to :project
  has_many :invoice_lines
  has_many :payments
end


app/models/payment.rb
class Payment < ApplicationRecord
  belongs_to :sale, optional: true
  belongs_to :purchase, optional: true
end

Elimiz değmişken optional'ları da yazdık çıktık. 



Ödemeler başlığı yanındaki "+" butonuna basarsak http://localhost:3000/payments/new?purchase_id=1 şeklinde bir adresleme ile alım faturasına ait ödeme eklemek için form açacaktır. Kontrolörümüz ve görsellerimiz hazır olmadığı için form boş gelecektir. Kontrolördeki new metodundan başlayalım. 

app/controllers/payments_controller.rb
...
  # GET /payments/new
  def new
    @payment = Payment.new
    if !params[:sale_id].nil?
      @payment.sale = Sale.find(params[:sale_id])
    elsif !params[:purchase_id].nil?
      @payment.purchase = Purchase.find(params[:purchase_id])
    end
  end
...

Hazır kontrolörü açmışken en allta bi permit kısıtlaması vardı ona da müdahale edelim.

app/controllers/payments_controller.rb
...
    # Only allow a list of trusted parameters through.
    def payment_params
      params.require(:payment).permit(:sale_id, :purchase_id, :note, :date, :value)
    end
end

Form düzenlemeleri geçen sefer ayrıntılı anlattık. Burada formu tek tek yapmayalım. Toptan yapalım.

app/views/payments/_form.html.erb
...
  <div class="form-group col-sm-8">
    <%= form.label "Firması :" %>
    <%= form.collection_select("company_id", Company.all, :id, :name, 
      {:include_blank => true, 
        selected: @payment.sale.nil? ? 
          (@payment.purchase.nil? ? nil : 
            @payment.purchase.project.company_id) : 
          @payment.sale.project.company_id}, 
      { class: "form-control", id: "company-select" }) %>
  </div>

  <div class="form-group col-sm-8">
    <%= form.label "Projesi :" %>
    <%= form.collection_select("project_id", @payment.sale.nil? ? 
      (@payment.purchase.nil? ? Project.all : Project.where(company_id: @payment.purchase.project.company_id)) : 
      Project.where(company_id: @payment.sale.project.company_id), :id, :name, 
      { include_blank: true, 
        selected: @payment.sale.nil? ? 
          (@payment.purchase.nil? ? nil :
            @payment.purchase.project_id) : 
          @payment.sale.project_id }, 
      { class: "form-control", id: "project-select" }) %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Satış Faturası :" %>
    <%= form.collection_select(:sale_id,  @payment.sale.nil? ? 
      (@payment.purchase.nil? ? Sale.all : Sale.where(project_id: @payment.purchase.project_id)) : 
      Sale.where(project_id: @payment.sale.project_id), :id, :name, 
      { include_blank: true,
        selected: @payment.sale.nil? ? nil : @payment.sale.id }, 
      { class: "form-control", id: "sale-select" }) %>
  </div>

  <div class="form-group col-sm-6">
    <%= form.label "Alım Faturası :" %>
    <%= form.collection_select(:purchase_id, @payment.purchase.nil? ? 
      (@payment.sale.nil? ? Purchase.all : Purchase.where(project_id: @payment.sale.project_id)) : 
      Purchase.where(project_id: @payment.purchase.project_id), :id, :name, 
      { include_blank: true,
        selected: @payment.purchase.nil? ? nil : @payment.purchase.id }, 
      { class: "form-control", id: "purchase-select" }) %>
  </div>

...
<%= javascript_tag do %>
...
  $("#project-select").change(function(){
    if(this.value){
...
      $.ajax({url: "/projects/getPurchases?id=" + this.value, success: function(result){
        var purchase_select = $("#purchase-select");
        purchase_select.empty();
        $.each(result, function(index, value){
          var opt = $("<option/>");
          opt.attr("value", value[0]);
          opt.text(value[1]);
          opt.appendTo(purchase_select);
        });
        $("<option/>").attr("selected", "selected").attr("value", 0).text("").prependTo(purchase_select);
      }});
    };
  });
<% end %>

Bir ödeme kaydı girdiğimizde ayrıntı sayfasına girmeyip hata verecektir. Ödeme ayrıntı sayfasını da düzenleyelim.

app/views/payments/show.html.erb
...
<div class="row">
  <div class="col-sm-12">
    <p>
      <strong class="col-sm-3">Satış Faturası :</strong>
      <%= @payment.sale.nil? ? "..." : (link_to @payment.sale.name, @payment.sale) %>
    </p>

    <p>
      <strong class="col-sm-3">Alım Faturası :</strong>
      <%= @payment.purchase.nil? ? "..." : (link_to @payment.purchase.name, @payment.purchase) %>
    </p>
...




Alım Fatura ile İlgili Toplam Değerler

Bir sürü yerde toplamlar, kar zarar borç alacak koyalım şimdi de. Önce alım fatura ayrıntısında borcumuzu yazalım.

app/views/purchases/show.html.erb
...
  <div class="col-sm-2">
    <h3>Net Borç</h3>
      <% net_total = purchase_total(@purchase).to_f - purchase_payment_total(@purchase).to_f %>
    <h3 id="net-total" class="text-center" style="background-color:<%= net_total > 1 ? 'pink' : 'lime' %>">
      <%= "%.2f" % net_total %>
    </h3>
  </div>
</div>
...

Boş bıraktığımız sağ üst köşedeki 2 sütunluk yere aynı satış faturasındaki gibi toplam fatura ve toplam ödeme arasındaki fark hesaplanıyor, ama bu sefer JavaScript yerine Ruby kullandık. 



Alım faturaları listesinde toplam ve borç sütunlarını da ekleyelim.

app/views/purchases/index.html.erb
...
        <th>Ödeme Tarihi</th>
        <th>Toplam</th>
        <th>Borç</th>
        <th colspan="2"></th>
      </tr>
    </thead>

    <tbody>
...
          <td><%= purchase_total(purchase) %></td>
          <% net_total = purchase_total(purchase).to_f - purchase_payment_total(purchase).to_f %>
          <td class="h4" style="color:<% if (net_total > 1) %>red<% else %>blue<% end %>"><%= "%.2f" % net_total %></td>
...

http://localhost:3000/purchases sayfamız artık şöyle görünüyor.



Bir şey unutmuşuz proje ayrıntı sayfasında Alım Faturaları başlığı yanındaki "+" butonuna basınca yeni alım faturası formu açılıyor ama firma ve proje seçili gelmiyor. Alım faturaları kontrolöründe new metodunu düzenlememiz gerekiyor.

app/controllers/purchases_controller.rb
...
  # GET /purchases/new
  def new
    @purchase = Purchase.new
    if !params[:project_id].nil?
      @purchase.project = Project.find(params[:project_id])
    end
  end
...

Şimdi projeden tıklayarak gidince firma ve proje seçili gelmeye başladı,



Proje ayrıntı sayfasında alım faturaları listesine de borç miktarını yazan sütun ekleyelim.

app/views/projects/show.html.erb
...
            <th>İsim</th>
            <th>Alım Tarihi</th>
            <th>Ödeme Tarihi</th>
            <th>Toplam</th>
            <th>Borç</th>
          </tr>
...
              <td><%= purchase_total(purchase) %></td>
              <% net =  purchase_total(purchase).to_f - 
                purchase_payment_total(purchase).to_f %>
              <td style="color: <%= net > 1 ? 'red' : 'blue' %>;"><%= "%.2f" % net %></td>
            </tr>
          <% end %>
        </tbody>
      </table>
...

Proje ayrıntı sayfasında alım faturaları bölümü şöyle görünecektir.



Bu sayfaya 2 tane toplam miktarı kocaman yazmak gerek diye düşünüyorum. İlki tüm ödemeler bittiğinde projenin bize ne kar getirdiği. Yani satış faturalarından gelmesi beklenen toplam para eksi alım faturalarına karşılık ödememiz gereken toplam para. İkincisi ise ödemeler olarak şu anda neredeyiz. Yani müşteriden şimdiye kadar ne kadar para almışız eksi alımlara şimdiye kadar ne kadar para ödemişiz. 

Sağ üst köşe boşluğuna bu ilaveleri yapalım.

app/views/projects/show.html.erb
...
    <strong class="col-sm-2">Not :</strong>
    <%= @project.note %>
  </p>
  </div>
  <div class="col-sm-2">
    <h3>Net Kar</h3>
      <% net_total = project_invoice_total(@project).to_f - project_purchase_total(@project).to_f %>
    <h3 id="net-total" class="text-center" style="background-color:<%= net_total > 1 ? 'lime' : 'pink' %>">
      <%= "%.2f" % net_total %>
    </h3>

    <h3>Anlık Net</h3>
      <% net_total = project_payment_total(@project).to_f - project_purchase_payment_total(@project).to_f %>
    <h3 id="net-total" class="text-center" style="background-color:<%= net_total > 1 ? 'lime' : 'pink' %>">
      <%= "%.2f" % net_total %>
    </h3>
  </div>
</div>
...

Şimdi burada kullanılan 4 adet toplam hesaplama metodunu helper dosyasına yazalım.

app/helpers/projects_helper.rb
module ProjectsHelper
    def project_invoice_total(project)
        total = 0
        project.sales.each do |sale|
            total += invoice_total(sale).to_f
        end
        "%.2f" % total
    end

    def project_purchase_total(project)
        total = 0
        project.purchases.each do |purchase|
            total += purchase_total(purchase).to_f
        end
        "%.2f" % total
    end

    def project_payment_total(project)
        total = 0
        project.sales.each do |sale|
            total += payment_total(sale).to_f
        end
        "%.2f" % total
    end

    def project_purchase_payment_total(project)
        total = 0
        project.purchases.each do |purchase|
            total += purchase_payment_total(purchase).to_f
        end
        "%.2f" % total
    end
end

project_invoice_total projeye karşılık bizim kestiğimiz faturaların toplam değerini veriyor. project_purchase_total proje için yaptığımız mal ve hizmet alım faturalarının toplam değerini veriyor. Bu ikisinin farkı da net kar olarak sayfada yer alıyor.

project_payment_total proje için kestiğimiz faturalara yapılan ödemelerin toplamını veriyor. project_purchase_payment_total ise aldığımız alım faturalarına karşılık bizim ödediğimiz paraların toplamını veriyor. İkisinin farkı şu anda net olarak nerede olduğumuzu gösteriyor. Bu da sayfada Anlık Net olarak gösteriliyor. Tüm ödemeler bitince yukarıda ve aşağıda aynı rakamlar olacaktır.

Sayfa görünümü şöyle oldu,



Benim için bu kadarı yetti ve uygulamamı kullanmaya başladım. Tabi ki yapılabilecek daha bir sürü şey var. Faturalara müşteri ya da tedarikçi firma seçimi eklenmesi. Vergi hesaplamaları, ki mutlaka lazım çünkü ben yukarıdaki rakama bakınca onu cebime kalan olarak düşünüyorum. Halbuki o rakamın içinde %18 kdv ve %20 civarı gelir vergisi ödemem gerekiyor. En azından yaklaşık bir hesap yapsam iyi olur. İleride kesilecek faturalar önce teklif olsa sonra teklif önaylanınca ileri tarihli fatura olacak iş bitince gerçek faturaya dönecek falan. Banka hesaplarını dahil edip, ödemelerin oraya eşleştirilmesi vs. Bakalım, kullandıkça ihtiyaçlar oluşacak. Şimdilik kalın sağlıcakla..




Hiç yorum yok:

Yorum Gönder