Kamis, 18 September 2014

Membuat Aplikasi POS dengan Ruby on Rails 4 part 2

Pada post sebelumnya  kita sudah mengerjakan desain dan model aplikasi, sekarang kita akan lanjutkan ke fungsi dan  bagian yang belum lengkapnya.

Fungsi Generate Code

Product mempunyai attribut code dan codenya nanti akan di generate secara otomatis.
Attribut ini nantinya bisa digunakan untuk barcode.
  1. Pada folder view/productIndex dan formnya dirubah
  2. File _form.html.erb bagian user dan codenya di hilangkan 
  3.  <%= form_for(@product) do |f| %>  
      <% if @product.errors.any? %>  
       <div id="error_explanation">  
        <h2><%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:</h2>  
        <ul>  
        <% @product.errors.full_messages.each do |message| %>  
         <li><%= message %></li>  
        <% end %>  
        </ul>  
       </div>  
      <% end %>  
      <div class="field">  
       <%= f.label :name %><br>  
       <%= f.text_field :name %>  
      </div>  
      <div class="field">  
       <%= f.label :price %><br>  
       <%= f.text_field :price %>  
      </div>  
      <div class="actions">  
       <%= f.submit %>  
      </div>  
     <% end %>  
    
  4. Untuk index.html.erb codenya seperti berikut
  5.  <h1>Listing Product</h1>  
     <table class="table table-striped">  
      <thead>  
       <tr>  
        <th>Name</th>  
        <th>Code</th>  
        <th>Price</th>  
        <th></th>  
        <th colspan="3"></th>  
       </tr>  
      </thead>  
      <tbody>  
       <% @products.each do |product| %>  
        <tr>  
         <td><%= product.name %></td>  
         <td><%= product.code %></td>  
         <td><%= product.price %></td>  
         <td><%= link_to 'Show', product %></td>  
         <td><%= link_to 'Edit', edit_product_path(product) %></td>  
         <td>  
           <%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %>  
         </td>  
        </tr>  
       <% end %>  
      </tbody>  
     </table>  
     <br>  
     <%= link_to 'New Product', new_product_path %>  
    
  6. Tambahkan code pada model product
  7.   before_create :set_code  
      def generate_code(size = 6)  
       charset = %w{ 2 3 4 6 7 9 A C D E F G H J K M N P Q R T V W X Y Z}  
       (0...size).map{ charset.to_a[rand(charset.size)] }.join  
      end  
      def set_code  
       self.code = generate_code(6)  
      end  
    
  8. Selanjutnya di controller productnya  tambahkan baris berikut pada method create
  9.  @product = Product.new(product_params)   
     @product.user_id = current_user.id #tambahkan code ini setelah code diatas  
    
  10. Lakukan input data di url http://localhost:3000/products/new

Membuat Nested Form 

  1. Edit model sale.rb tambahkan code berikut
  2.  has_many :items  
     accepts_nested_attributes_for :items, allow_destroy: true  
    
  3. Edit partial _form.html.erb di dalam folder view/sales
  4.  <%= form_for(@sale) do |f| %>  
      <% 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="field">  
       <%= f.label :name %><br>  
       <%= f.text_field :name %>  
      </div>  
      <%= f.fields_for :items do |builder| %>   
        <%= render 'item_fields', f: builder %>   
      <% end %>   
      <%= link_to_add_fields "Add Item", f, :items %>   
      <div class="actions">  
       <%= f.submit %>  
      </div>  
     <% end %>  
     <script type="text/javascript">   
      jQuery(function() {   
       $('form').on('click', '.remove_fields', function(event) {   
       $(this).prev('input[type=hidden]').val('1');   
       $(this).closest('fieldset').hide();   
       return event.preventDefault();   
       });   
       return $('form').on('click', '.add_fields', function(event) {   
       var regexp, time;   
       time = new Date().getTime();   
       regexp = new RegExp($(this).data('id'), 'g');   
       $(this).before($(this).data('fields').replace(regexp, time));   
       return event.preventDefault();   
       });   
      });   
      </script>   
    
  5. Edit aplication_helper.rb tambahkan code berikut
  6.   def link_to_add_fields(name, f, association)  
       new_object = f.object.send(association).klass.new  
       id = new_object.object_id  
       fields = f.fields_for(association, new_object, child_index: id) do |builder|  
        render(association.to_s.singularize + "_fields", f: builder)  
       end  
       link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})  
      end 
    
  7. buat file partial _item_fields.html.erb di folder sales/app/views/sales/ isinya seperti berikut
  8.  <fieldset>  
      <%= f.label :product, "Product" %>  
      <%= f.collection_select :product_id, Product.all, :id, :name %>  
      <%= f.label :quantity, "Quantity" %>  
      <%= f.text_field :quantity, class: 'padli' %>  
      <%= f.hidden_field :_destroy %>  
      <%= link_to "remove", '#', class: "remove_fields" %>  
     </fieldset>  
    
  9. Periksa di http://localhost:3000/sales/new hasilnya akan seperti gambar berikut

Fungsi Hitung Penjualan 

Tadikan di form penjualan kita sudah bisa input item dan jumlahnya,  tapi total penjualanya belum terhitung. Nah sekarang kita akan buat menghitung total nya:
  1. Edit model item ketikan code berikut:
  2.   before_save :set_total  
      def set_total  
       if self.quantity.blank?  
        0  
       else  
            self.total = self.quantity * self.product.price  
       end  
      end  
      def subtotal  
       if self.quantity.blank?  
        0  
       else  
            self.quantity * self.product.price  
       end  
      end  
    
  3. Edit model sale untuk menghitung total harga penjualan berikut codenya
  4.   def subtotals  
       self.items.map { |i| i.subtotal }  
      end  
      def total_all  
       subtotals.sum  
      end  
    
  5. Edit controllers sales_controller.rb
  6. Tambahkan pada method create code berikut
  7.  @sale = Sale.new(sale_params)  
     @sale.user_id = current_user.id #tambahkan ini setelah code di atas  
     @sale.total = @sale.total_all #tambahkan ini setelah code di atas  
    
  8. Tambahkan parameter yang akan di permit
  9.  params.require(:sale).permit(:name, items_attributes: [:id,:product_id, :price,:quantity,:total,:_destroy])  
    
  10. Lakukan input data penjualan  http://localhost:3000/sales/new tambahkan beberapa item kemudian simpan
  11. Periksa apakah total penjualanya terhitung
  12. Edit file show di folder view sale
  13.  <p id="notice"><%= notice %></p>  
     <p>  
      <strong>Name:</strong>  
      <%= @sale.name %>  
     </p>  
     <%= link_to 'Edit', edit_sale_path(@sale) %> |  
     <%= link_to 'Back', sales_path %>  
     <h1>Listing Item</h1>  
     <table class="table table-striped">  
      <thead>  
       <tr>  
        <th>Product</th>  
        <th>price</th>  
        <th>quantity</th>  
        <th>total</th>  
        <th></th>  
       </tr>  
      </thead>  
      <tbody>  
       <% @sale.items.each do |item| %>  
        <tr>  
         <td><%= item.product.name %></td>  
         <td><%= item.product.price %></td>  
         <td><%= item.quantity %></td>  
         <td><%= item.total %></td>  
        </tr>  
       <% end %>  
      </tbody>  
     </table>  
     <hr>  
      <p> Total </p>  
      <%= @sale.total%>  
     <hr>  
    

Mengatur User-Roles

Pada bagian ini kita akan mengatur hak akses user pada aplikasi POS.
  1. Generate cancan
  2. $ rails g cancan:ability
  3. Tambahkan code di class ability.rb seperti berikut: 
  4.  class Ability  
      include CanCan::Ability  
      def initialize(user)  
       if user.present?  
        if user.role.name == 'admin'  
         can :manage, :all  
        else  
         can :create , Product  
         can :create , Sale  
         can :read, :all  
        end  
       else  
        can :read, :all  
       end  
      end  
     end  
    
  5.  Edit products_controller tambahkan  load and authorize seperti berikut 
  6.  class ProductsController < ApplicationController  
      before_action :set_product, only: [:show, :edit, :update, :destroy]  
      load_and_authorize_resource  
      # GET /products  
      # GET /products.json  
      def index  
       @products = Product.all  
      end  
      # GET /products/1  
      # GET /products/1.json  
      def show  
      end  
      # GET /products/new  
      def new  
       @product = Product.new  
      end  
      # GET /products/1/edit  
      def edit  
      end  
      # POST /products  
      # POST /products.json  
      def create  
       @product = Product.new(product_params)  
       @product.user_id = current_user.id #tambahkan code ini setelah code diatas   
       respond_to do |format|  
        if @product.save  
         format.html { redirect_to @product, notice: 'Product was successfully created.' }  
         format.json { render :show, status: :created, location: @product }  
        else  
         format.html { render :new }  
         format.json { render json: @product.errors, status: :unprocessable_entity }  
        end  
       end  
      end  
      # PATCH/PUT /products/1  
      # PATCH/PUT /products/1.json  
      def update  
       respond_to do |format|  
        if @product.update(product_params)  
         format.html { redirect_to @product, notice: 'Product was successfully updated.' }  
         format.json { render :show, status: :ok, location: @product }  
        else  
         format.html { render :edit }  
         format.json { render json: @product.errors, status: :unprocessable_entity }  
        end  
       end  
      end  
      # DELETE /products/1  
      # DELETE /products/1.json  
      def destroy  
       @product.destroy  
       respond_to do |format|  
        format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }  
        format.json { head :no_content }  
       end  
      end  
      private  
       # Use callbacks to share common setup or constraints between actions.  
       def set_product  
        @product = Product.find(params[:id])  
       end  
       # Never trust parameters from the scary internet, only allow the white list through.  
       def product_params  
        params.require(:product).permit(:code, :name, :price, :user_id)  
       end  
     end  
    
  7. Edit sales_controller tambahkan  load and authorize seperti berikut
  8.  class SalesController < ApplicationController  
      before_action :set_sale, only: [:show, :edit, :update, :destroy]  
      load_and_authorize_resource  
      # GET /sales  
      # GET /sales.json  
      def index  
       @sales = Sale.all  
      end  
      # GET /sales/1  
      # GET /sales/1.json  
      def show  
      end  
      # GET /sales/new  
      def new  
       @sale = Sale.new  
      end  
      # GET /sales/1/edit  
      def edit  
      end  
      # POST /sales  
      # POST /sales.json  
      def create  
       @sale = Sale.new(sale_params)  
       @sale.user_id = current_user.id #tambahkan ini setelah code di atas   
       @sale.total = @sale.total_all #tambahkan ini setelah code di atas  
       respond_to do |format|  
        if @sale.save  
         format.html { redirect_to @sale, notice: 'Sale was successfully created.' }  
         format.json { render :show, status: :created, location: @sale }  
        else  
         format.html { render :new }  
         format.json { render json: @sale.errors, status: :unprocessable_entity }  
        end  
       end  
      end  
      # PATCH/PUT /sales/1  
      # PATCH/PUT /sales/1.json  
      def update  
       respond_to do |format|  
        if @sale.update(sale_params)  
         format.html { redirect_to @sale, notice: 'Sale was successfully updated.' }  
         format.json { render :show, status: :ok, location: @sale }  
        else  
         format.html { render :edit }  
         format.json { render json: @sale.errors, status: :unprocessable_entity }  
        end  
       end  
      end  
      # DELETE /sales/1  
      # DELETE /sales/1.json  
      def destroy  
       @sale.destroy  
       respond_to do |format|  
        format.html { redirect_to sales_url, notice: 'Sale was successfully destroyed.' }  
        format.json { head :no_content }  
       end  
      end  
      private  
       # Use callbacks to share common setup or constraints between actions.  
       def set_sale  
        @sale = Sale.find(params[:id])  
       end  
       # Never trust parameters from the scary internet, only allow the white list through.  
       def sale_params  
        params.require(:sale).permit(:name, items_attributes: [:id,:product_id, :price,:quantity,:total,:_destroy])  
       end  
     end  
    
  9. Edit aplication_controller tambahkan baris code berikut
  10.   rescue_from CanCan::AccessDenied do |exception|  
       flash[:error] = "Access denied."  
       redirect_to root_url  
      end  
    
  11. Untuk link tinggal di kasih kondisi seperti berikut
  12.      <td><%= link_to 'Show', sale %></td>  
         <% if can? :update, Sale %>  
          <td><%= link_to 'Edit', edit_sale_path(sale) %></td>  
         <%end%>  
         <% if can? :destroy, Sale %>  
          <td><%= link_to 'Destroy', sale, method: :delete, data: { confirm: 'Are you sure?' } %></td>  
         <% end %>  
    

Public Activities

Fitur ini bertujuan untuk mencatat aktifitas user pada aplikasi. Sehingga apabila ada karyawan yang melakukan aktifitas pelanggaran / kecurangan, sistem admin bisa melihat bukti aktifitasnya.
  1. Generate public_activity
  2. $ rails g public_activity:migration
    $ rake db:migrate
  3. Di aplication_controller.rb tambahkan code
  4.  include PublicActivity::StoreController  
    
  5. Di model product.rb dan sale.rb  tambahkan code berikut
  6.  include PublicActivity::Model  
      tracked owner: ->(controller, model) { controller && controller.current_user}  
    
  7. Buat controller untuk  activities
  8. $ rails g controller activities 
  9. Di routesnya tambahkan code
  10.   root to: 'home#index'  
      resources :activities  
    
  11. Di controllernya tambahkan code berikut 
  12.  class ActivitiesController < ApplicationController  
      def index  
       @activities = PublicActivity::Activity.order("created_at desc")  
      end  
     end  
    
  13. Di viewnya buat file index.html.erb di folder activities isi dengan code berikut
  14.  <h1>Listing Activities</h1>  
     <table class="table table-striped table-bordered table-condensed sortable">  
       <thead>  
         <tr>  
           <th><%= "Activities"%></th>  
         </tr>  
       </thead>  
       <tbody>  
            <% @activities.each do |activity| %>  
         <tr>  
           <td valign="top">   
             <%= activity.owner.email %>  
             <%= render_activity activity %>  
           </td>  
         </tr>  
         <% end %>  
       </tbody>  
       <tfoot>  
         <tr>  
           <td colspan="3"></td>  
         </tr>  
       </tfoot>  
     </table>  
    
  15. Buat folder public_activity di view
  16. Di dalam folder public_activity buat folder product dan sale
  17. Di dalam folder product dan sale buat file html partial _create.html.erb ,_update.html.erb, _destroy.html.erb
  18. Create.html.erb  codenya seperti berikut
  19.  added product  
     <% if activity.trackable %>  
      <%= link_to activity.trackable.name, product_path(activity.trackable.id) %>  
     <% else %>  
      which has since been removed  
     <% end %>  
    
  20. _update.html.erb
  21.  Updated product  
     <% if activity.trackable %>  
      <%= link_to activity.trackable.name, product_path(activity.trackable.id) %>  
     <% else %>  
      which has since been removed  
     <% end %>  
    
  22. _destroy.html.erb
  23.  removed a produc  
    
  24. Masuk folder layout dan edit file application.html.erb tambahkan code dibawah class nav navbar-nav
  25.  ·<li><%= link_to "All Activities", activities_path %></li>  
    
  26. Terakhir lakukan proses insert, update dan delete di http://localhost:3000/sales dan http://localhost:3000/products
  27. Hasilnya  bisa di akses di http://localhost:3000/activities

Membuat Aplikasi POS dengan Ruby on Rails 4 part 1

Pengelolaan keuangan adalah salah satu hal pokok yang harus diperhatikan oleh usaha kecil dan menengah (UKM). Untuk membantu memantau kondisi bisnis, kita membutuhkan software Point of Sales ( POS) sederhana yang dapat membantu mencatat aktivitas transaksi. Berikut beberapa fitur yang akan di bangun :
  1. Management Barang
  2. Management Penjualan
  3. Management User + Login

Persiapan

Pastikan di komputermu sudah terinstall:

  1. Ruby versi 2.x
  2. Rails versi 4.x
  3. Database Mysql 
  4. Mozila Firefox   
Kemudian berikut adalah Gems yang akan kita gunakan:
  1. Devise
  2. Cancan
  3. Nested Form
  4. Public Activity

Buat Project Baru 

  1. Membuat project baru dengan mysql
  2. $ rails new sales -d mysql 
    $ cd sales
  3. Edit gemfile tambahkan code baris berikut
  4.   gem 'devise'   
      gem "cancancan"   
      gem "nested_form"    
      gem 'public_activity'  
    
    $ bundle install

Memasang Bootstraps

  1. Buka url http://getbootstrap.com/getting-started/#download
  2. Setelah download copy dan paste isinya ke dalam folder sales/app/assets
  3. Semua file di folder  css copy dan paste  di sale/app/stylesheets
  4. Semua file di folder js copy dan paste di sale/app/javascripts

Home

  1. kita buat controller dan foldernya view lewat comand
  2. rails g controller home 
  3. Buat file index di view/home
  4. Isi dengan <p>welcome</p>
  5. Edit config/routes.rb tambahkan kode berikut
  6.  root to: 'home#index'  
    

Memasang Devise

OK sampai sini bootstrap dan homenya sudah dibuat, sekarang kita akan buat login untuk user, berikut langkahnya
  1. Generate devise 
  2. $ rake db:create
    $ rails generate devise:install
    $ rails generate devise User
    $ rails generate model role name:string
    $ rails g migration addRoleIdToUser role_id:integer
  3. Setelah selesai lakukan migration database
  4. $ rake db:migrate
  5. Masuk ke folder app -> models kemudian Edit file model user dan role.rb
     class User < ActiveRecord::Base  
        belongs_to :role
        devise :database_authenticatable, :registerable,
             :recoverable, :rememberable, :trackable, :validatable
    end
    
  6.   
     class Role < ActiveRecord::Base  
        has_many :users  
     end  
    
  7. Edit seed.rb di folder db
  8.  r1 = Role.create(:name => 'user')  
     r2 = Role.create(:name => 'admin')  
     us1 = User.create(:email => 'user@gmail.com' , :password => 'q1w2e3r4', :role_id => r1.id)   
     us2 = User.create(:email => 'admin@gmail.com' , :password => 'q1w2e3r4', :role_id => r2.id)  
    
  9. Untuk memasukan data jalankan perintah berikut
    $ rake db:seed
  10. Untuk membuat user yang sign_up defautlnya adalah role user tambahkan code berikut di model user.rb
  11.   before_create :set_default_role  
      private  
      def set_default_role  
       self.role ||= Role.find_by_name('user')  
      end  
    
  12. Untuk menjalankan server ketikan code berikut di terminal 
  13. $ rails s
  14. Buka browser ketikan http://localhost:3000/users/sign_in maka akan tampil halaman seperti berikut 

Layout

Kita akan membuat desain utama aplikasi ini ,cukup mudah karena desainnya sangat sederhana
  1. Edit file application.html.erb
  2.   <!DOCTYPE html>   
      <html>   
      <head>   
        <title>Sale</title>   
        <%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>   
        <%= javascript_include_tag "application", "data-turbolinks-track" => true %>   
        <%= csrf_meta_tags %>   
      </head>   
      <body>   
        <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">   
           <div class="container">   
             <div class="navbar-header">   
                <a class="navbar-brand" href="#">Sale</a>   
             </div>   
             <ul class="nav navbar-nav">    
             </ul>   
             <ul class="nav navbar-nav navbar-right">   
                <% if user_signed_in? %>   
                <li><%= link_to current_user.email, edit_user_registration_path %></li>   
                <li><%= link_to "Log Out" , destroy_user_session_path, method: :delete %></li>   
                <% else %>   
                <li><%= link_to "Sign In", user_session_path %></li>   
                <li><%= link_to "Register", new_user_registration_path %></li>   
                <% end %>   
             </ul>   
           </div>   
        </div>   
        <div class="container">   
           <% flash.each do |type, message| %>   
           <div class="alert <%= flash_class type %> alert-dismissable">   
             <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>   
             <p><%= message %></p>   
           </div>   
           <% end %>   
           <%= yield %>   
        </div>   
      </body>   
      </html>   
    
  3. Edit application_helper.rb
  4.  def flash_class(type)  
      case type  
      when :alert  
        "alert-danger"  
      when :notice  
        "alert-success"  
       else  
        "" end  
     end  
    
  5. Edit file aplication.css di folder app/assets/stylesheet
  6.  body {  
           padding-top: 70px;  
     }  
    
  7. Layoutnya nanti akan seperti gambar berikut

Generate Model dan Controller

Kita akan generate model dan controller, tujuannya agar tidak buat file satu persatu  
  1. Scaffold untuk generate view model dan controller  
  2. $ rails g scaffold product code:string name:string price:decimal user:belongs_to
    $ rails g scaffold sale name:string total:decimal user:belongs_to
  3. Model untuk generate model saja
  4. $ rails g model item product:belongs_to sale:belongs_to quantity:decimal total:decimal
  5.  Setelah selesai databasenya di migrate atau di reset ulang 
  6. $ rake db:migrate
  7. Masuk folder model pada file product tambahkan code berikut
  8.  has_many :items  
    
  9. Masuk folder model pada file sale tambahkan code berikut
  10.  has_many :items  
    
  11. Edit form partial _form.html.erb di folder view/products dan view/sales hapus baris code berikut
  12.   <div class="field">  
       <%= f.label :user_id %><br>  
       <%= f.text_field :user_id %>  
      </div>  
    
  13. Edit file index.html.erb di folder view/products hapus baris code berikut
  14.  <th>User</th>  
    
     <td><%= product.user %></td>  
    
  15. Edit file index.html.erb di folder view/sales hapus baris code berikut
  16.  <th>User</th>  
    
     <td><%= sale.user %></td>  
    
  17. Untuk memasang tema bootstrap ke dalam tabel edit index.html.erb di folder products and sales perhatikan baris <table> dan tambahkan code berikut
  18.  <table class="table table-striped">  
    
  19. Edit aplication.html.erb di folder layout tambahkan baris code setelah tag <ul class="nav navbar-nav"> </ul>
  20.  <li><%= link_to "All Sales", sales_path %></li>  
     <li><%= link_to "All Products", products_path %></li>  
    
  21. View tablenya akan seperti berikut


Untuk selanjutnya silahkan cek link ini: Membuat Aplikasi POS dengan Ruby on Rails 4 Part 2