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

Comments

Popular posts from this blog

Seri Belajar Ruby on Rails Bagian 9 - Membuat Autentikasi dengan Devise

Seri Belajar Ruby on Rails Bagian 6 - Membuat Table & Dummy Data

Seri Belajar Ruby on Rails Bagian 7 - Memahami ActiveRecord