Compare commits

..

No commits in common. "master" and "feature-12-update-contact" have entirely different histories.

83 changed files with 614 additions and 1233 deletions

1
.gitignore vendored
View File

@ -25,4 +25,3 @@ config/database.yml
.env* .env*
lolcommit.yml lolcommit.yml
*.swp

28
Gemfile
View File

@ -1,5 +1,6 @@
source 'https://rubygems.org' source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.1' gem 'rails', '4.2.1'
# Use sqlite3 as the database for Active Record # Use sqlite3 as the database for Active Record
@ -15,7 +16,6 @@ gem 'coffee-rails', '~> 4.1.0'
# Use jquery as the JavaScript library # Use jquery as the JavaScript library
gem 'jquery-rails' gem 'jquery-rails'
gem 'jquery-ui-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks' gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
@ -50,25 +50,23 @@ end
# Web Server # Web Server
gem 'puma' gem 'puma'
# Environnement .env
gem 'dotenv-rails'
# Database # Database
gem 'pg' gem 'pg'
# Users
gem 'devise'
# Upload # Upload
gem 'carrierwave' gem 'carrierwave'
# Commentable items # Environnement .env
gem 'acts_as_commentable' gem 'dotenv-rails'
# Users
# HTML Templating gem 'devise'
gem 'slim-rails'
# Bootstrap
gem "twitter-bootstrap-rails"
# Pagination # Pagination
gem 'will_paginate' gem 'will_paginate'
# Bootstrap
# Bootstrap
# gem 'bootstrap-sass'
# gem "therubyracer"
# gem "less-rails" #Sprockets (what Rails 3.1 uses for its asset pipeline) supports LESS
gem "twitter-bootstrap-rails"
# Bootstrap for pagination # Bootstrap for pagination
gem 'bootstrap-will_paginate' gem 'bootstrap-will_paginate'
# Autocomplete for ids # HTML Templating
gem 'rails-jquery-autocomplete' gem 'slim-rails'

View File

@ -36,8 +36,7 @@ GEM
minitest (~> 5.1) minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4) thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1) tzinfo (~> 1.1)
acts_as_commentable (4.0.2) arel (6.0.2)
arel (6.0.3)
bcrypt (3.1.10) bcrypt (3.1.10)
binding_of_caller (0.7.2) binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1) debug_inspector (>= 0.0.1)
@ -75,7 +74,7 @@ GEM
railties (~> 4.0) railties (~> 4.0)
erubis (2.7.0) erubis (2.7.0)
execjs (2.5.2) execjs (2.5.2)
globalid (0.3.6) globalid (0.3.5)
activesupport (>= 4.1.0) activesupport (>= 4.1.0)
i18n (0.7.0) i18n (0.7.0)
jbuilder (2.3.1) jbuilder (2.3.1)
@ -85,8 +84,6 @@ GEM
rails-dom-testing (~> 1.0) rails-dom-testing (~> 1.0)
railties (>= 4.2.0) railties (>= 4.2.0)
thor (>= 0.14, < 2.0) thor (>= 0.14, < 2.0)
jquery-ui-rails (5.0.5)
railties (>= 3.2.16)
json (1.8.3) json (1.8.3)
loofah (2.0.2) loofah (2.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
@ -95,7 +92,7 @@ GEM
method_source (0.8.2) method_source (0.8.2)
mime-types (2.6.1) mime-types (2.6.1)
mini_portile (0.6.2) mini_portile (0.6.2)
minitest (5.8.0) minitest (5.7.0)
multi_json (1.11.2) multi_json (1.11.2)
nokogiri (1.6.6.2) nokogiri (1.6.6.2)
mini_portile (~> 0.6.0) mini_portile (~> 0.6.0)
@ -105,7 +102,7 @@ GEM
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.8.1) method_source (~> 0.8.1)
slop (~> 3.4) slop (~> 3.4)
puma (2.12.3) puma (2.12.1)
rack (1.6.4) rack (1.6.4)
rack-test (0.6.3) rack-test (0.6.3)
rack (>= 1.0) rack (>= 1.0)
@ -126,15 +123,13 @@ GEM
activesupport (>= 4.2.0.beta, < 5.0) activesupport (>= 4.2.0.beta, < 5.0)
nokogiri (~> 1.6.0) nokogiri (~> 1.6.0)
rails-deprecated_sanitizer (>= 1.0.1) rails-deprecated_sanitizer (>= 1.0.1)
rails-erd (1.4.2) rails-erd (1.4.1)
activerecord (>= 3.2) activerecord (>= 3.2)
activesupport (>= 3.2) activesupport (>= 3.2)
choice (~> 0.2.0) choice (~> 0.2.0)
ruby-graphviz (~> 1.2) ruby-graphviz (~> 1.2)
rails-html-sanitizer (1.0.2) rails-html-sanitizer (1.0.2)
loofah (~> 2.0) loofah (~> 2.0)
rails-jquery-autocomplete (1.0.3)
rails (>= 3.2)
railties (4.2.1) railties (4.2.1)
actionpack (= 4.2.1) actionpack (= 4.2.1)
activesupport (= 4.2.1) activesupport (= 4.2.1)
@ -201,7 +196,6 @@ PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
acts_as_commentable
bootstrap-will_paginate bootstrap-will_paginate
byebug byebug
carrierwave carrierwave
@ -210,13 +204,11 @@ DEPENDENCIES
dotenv-rails dotenv-rails
jbuilder (~> 2.0) jbuilder (~> 2.0)
jquery-rails jquery-rails
jquery-ui-rails
pg pg
pry pry
puma puma
rails (= 4.2.1) rails (= 4.2.1)
rails-erd rails-erd
rails-jquery-autocomplete
sass-rails (~> 5.0) sass-rails (~> 5.0)
sdoc (~> 0.4.0) sdoc (~> 0.4.0)
slim-rails slim-rails
@ -228,4 +220,4 @@ DEPENDENCIES
will_paginate will_paginate
BUNDLED WITH BUNDLED WITH
1.11.2 1.10.3

View File

@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found. the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.} {one line to give the program's name and a brief idea of what it does.}
Copyright (C) 2015 {name of author} Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode: notice like this when it starts in an interactive mode:
MorningPeak Copyright (C) 2015 Arthur Poulet {project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details. under certain conditions; type `show c' for details.

View File

@ -1,22 +1,11 @@
# Project Presentation # What is this application
_Morning Peak is a modern and OpenSource Web Application. _Morning Peak is a modern and OpenSource Web Application.
It has been designed to manage clients, bills, and issues for little and medium compagnies._ It has been designed to manage clients, bills, and issues for little and medium compagnies._
<img att="Dashboard Mobile view" src="http://imgur.com/bnYHYJ6l.png" width="200" /> <img att="Dashboard Mobile view" src="http://imgur.com/bnYHYJ6l.png" width="320" />
<img alt="Dashboard Desktop view" src="http://i.imgur.com/oxE9LR1.png" width="500" /> <img alt="Tickets Desktop view" src="http://i.imgur.com/e004zBZ.png" width="600" />
<img alt="Dashboard Desktop view" src="http://i.imgur.com/oxE9LR1.png" width="600" />
There is a lot of CRM on the web. Some of them are web application. Some of them are open source. Some of them are modern.
But, I __never see any of them grouping the 3__. It is why I started to develop this application.
To improve my skills, my knowledges, and to use it.
I want a simple application, that I __understand__, and that I __need__. By __simple__, I mean:
- No tasks, no reports, no chat. I want an application to do ONE thing, manage my clients, and it must do it clearly, and good.
- A pluggable application, with many __REST API__. Because tasks and reports are usefull.
- Generic items. I prefere __ONE kind of Bills + Tags__ than __4 ou 5 kinds of Bills__ (for example).
<img alt="Tickets Desktop view" src="http://i.imgur.com/e004zBZ.png" width="500" />
## Summary ## Summary
@ -24,25 +13,23 @@ I want a simple application, that I __understand__, and that I __need__. By __si
1. [Installation](#1-installation) 1. [Installation](#1-installation)
1. [Requirements](#11-requirements) 1. [Requirements](#11-requirements)
2. [Initialization](#12-initialization) 2. [Initialization](#12-initialization)
3. [Configuration](#13-configuration) 3. [First start](#13-first-start)
4. [First start](#14-first-start)
2. [Contributions](#2-contributions) 2. [Contributions](#2-contributions)
1. [Contributors](#21-contributors) 1. [Contributors](#21-contributors)
2. [How to contribute](#22-how-to-contribute-) 2. [How to contribute](#22-how-to-contribute-)
3. [License](#23-license)
3. [Architecture](#3-architecture)
1. [Modelisation](#31-modelisation)
# 1. Installation # 1. Installation
## 1.1. Requirements ## 1.1. Requirements
- Ruby 2.0 or greater. - Ruby 2.0 or greater.
- Postgresql server 9 or greater running with creditentials. - Postgresql server.
## 1.2. Initialization ## 1.2. Initialization
Start by pasting this script in your shell:
In your shell, start by using this script:
```bash ```bash
cd MorningPeak/ cd MorningPeak/
gem install bundler gem install bundler
@ -54,37 +41,21 @@ rake db:migrate
rake db:seed # will generate default data. Not on production ;) rake db:seed # will generate default data. Not on production ;)
``` ```
## 1.3. Configuration ## 1.3. First start
- You can create a file ``.env`` to save your locals cvars without pollute your global env.
- You can also create ``.env.production`` etc. for environement specifics cvars
- A ``.env`` file looks like:
```text
COMPANY: "Yolo production"
LOCALE: fr
...
```
- The application's specifics cvars are :
- COMPANY
## 1.4. First start
When you done with the configuration of the database (editing ``config/database.yml``), When you done with the configuration of the database (editing ``config/database.yml``),
you can run the server by the following command : you can run the server by the following command :
``` ```
rails s # "-b 0.0.0.0 -p 80" to test on internet :) rails s # "-b 0.0.0.0 -p 80" to test on internet :)
``` ```
The server will be accessible via [localhost:3000](http://localhost:3000) The server will be accessible via [localhost](http://localhost:3000)
Default creditentials are generated in the seed: Default identifiers, generated in the seed:
```text ``user> login: admin@jerevedunemaison.com , password: jrdm2015``
user> login: user@client.com , password: user2015
```
```text ``admin> login: admin@wir.com , password: wir2015``
admin> login: admin@admin.admin , password: wir2015
```
Checkout for [rails minidoc](RailsMinidoc.md) for a resume of rails. Checkout for [rails minidoc](RailsMinidoc.md) for a resume of rails.
@ -96,6 +67,7 @@ Checkout for [rails minidoc](RailsMinidoc.md) for a resume of rails.
<img alt="Look at this cute face" src="https://pbs.twimg.com/media/CJ_ErJ2W8AAdev3.jpg" width="200" height="150" /> <img alt="Look at this cute face" src="https://pbs.twimg.com/media/CJ_ErJ2W8AAdev3.jpg" width="200" height="150" />
## 2.2. How to contribute ? ## 2.2. How to contribute ?
You can contribute to this project by Merge Request on the gitlab repository [here](https://gitlab.com/poulet_a/MorningPeak). You can contribute to this project by Merge Request on the gitlab repository [here](https://gitlab.com/poulet_a/MorningPeak).
The best pratices are to create short commits, and short Merge Requests. Respect the git commit nomage convention as possible with: The best pratices are to create short commits, and short Merge Requests. Respect the git commit nomage convention as possible with:
@ -106,28 +78,3 @@ The best pratices are to create short commits, and short Merge Requests. Respect
We accept any kind of work : translations, bug fix, additionnal features, optimizations, documentation, etc. We accept any kind of work : translations, bug fix, additionnal features, optimizations, documentation, etc.
Don't be afraid ! Don't be afraid !
## 2.3. License
see the license in the ``License`` file.
It is under:
```text
GNU GENERAL PUBLIC LICENSE
```
# 3. Architecture
## 3.1 Modelisation
### Creation and belongs
- User has a Client (which is created when the user is created)
- Client has many Contacts and Bills
- User/Admin has many Tickets and Comments
### Permissions
- Admin can Comment, Read, Edit, Delete, and Create everything
- User can open Ticket, Anwser and Close them.
- User can Read every Bills wich is associated to him
- User can not read his client informations (like notes, ...)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

View File

@ -12,8 +12,6 @@
// //
//= require jquery //= require jquery
//= require jquery_ujs //= require jquery_ujs
//= require jquery-ui
//= require twitter/bootstrap //= require twitter/bootstrap
//= require jquery-ui/autocomplete //= require turbolinks
//= require autocomplete-rails
//= require_tree . //= require_tree .

View File

@ -1,11 +0,0 @@
commentableLoadComments = (base_url) ->
$.get(base_url + "/comments/about").done (e) ->
$("#comments").html(e)
$(document).ready ->
url = window.location.pathname
commentableLoadComments(url)
$(document).on "ajax:success", "#new_comment", (e, data, status, xhr) ->
commentableLoadComments(url)
$(document).on "ajax:complete", ".remove-comment", (e, data, status, xhr) ->
commentableLoadComments(url)

View File

@ -3,7 +3,7 @@
# You can use CoffeeScript in this file: http://coffeescript.org/ # You can use CoffeeScript in this file: http://coffeescript.org/
updateViewAtWhenClick = () -> updateViewAtWhenClick = () ->
$('.contact-link-view_at').bind('ajax:success', (event, data, status, xhr) -> $('.contact-link-view_at').bind('ajax:success', (event, data, status, xhr) ->
this.parentElement.children[7].textContent = data["view_at"] this.parentNode.childNodes[15].textContent = data["view_at"]
) )
$ -> $ ->

View File

@ -1,3 +0,0 @@
$ ->
# $("#contact_view_at").datepicker()
$(".form-date").datepicker({ dateFormat: 'yy-mm-dd' })

View File

@ -10,7 +10,6 @@
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
* file per style scope. * file per style scope.
* *
*= require jquery-ui
*= require_tree . *= require_tree .
*= require_self *= require_self
*= require "dashboard" *= require "dashboard"

View File

@ -1,8 +1,4 @@
class BillsController < ApplicationController class BillsController < ApplicationController
include CommentableForm
autocomplete :client, :name
before_action :set_bill, only: [:show, :edit, :update, :destroy] before_action :set_bill, only: [:show, :edit, :update, :destroy]
before_action :authenticate_admin! before_action :authenticate_admin!
@ -15,7 +11,6 @@ class BillsController < ApplicationController
# GET /bills/1 # GET /bills/1
# GET /bills/1.json # GET /bills/1.json
def show def show
prepare_comment_for @bill
end end
# GET /bills/new # GET /bills/new

View File

@ -1,6 +1,4 @@
class ClientTicketsController < ApplicationController class ClientTicketsController < ApplicationController
include CommentableForm
before_action :set_ticket, only: [:show, :edit, :update, :destroy] before_action :set_ticket, only: [:show, :edit, :update, :destroy]
before_action :set_ticket_custom_route, only: [:close, :open, :respond] before_action :set_ticket_custom_route, only: [:close, :open, :respond]
before_action :looks_ticket, only: [:show, :edit, :update, :close, :open] before_action :looks_ticket, only: [:show, :edit, :update, :close, :open]
@ -9,13 +7,13 @@ class ClientTicketsController < ApplicationController
# GET /tickets # GET /tickets
# GET /tickets.json # GET /tickets.json
def index def index
@tickets = current_user.tickets.order('state DESC') @tickets = current_user.tickets.heads.order('state DESC')
end end
def close def close
respond_to do |format| respond_to do |format|
if @ticket.close if @ticket.close
@ticket.update(admin_view_at: Time.now) # add comment ? @ticket.update(admin_view_at: Time.now)
format.html { redirect_to client_ticket_url(@ticket), notice: 'Ticket was successfully closed.' } format.html { redirect_to client_ticket_url(@ticket), notice: 'Ticket was successfully closed.' }
format.json { render :show, status: :ok, location: client_tickets_url(@ticket) } format.json { render :show, status: :ok, location: client_tickets_url(@ticket) }
else else
@ -28,7 +26,7 @@ class ClientTicketsController < ApplicationController
def open def open
respond_to do |format| respond_to do |format|
if @ticket.open if @ticket.open
@ticket.update(admin_view_at: nil) # add comment ? @ticket.update(admin_view_at: nil)
format.html { redirect_to client_ticket_url(@ticket), notice: 'Ticket was successfully reopened.' } format.html { redirect_to client_ticket_url(@ticket), notice: 'Ticket was successfully reopened.' }
format.json { render :show, status: :ok, location: client_tickets_url(@ticket) } format.json { render :show, status: :ok, location: client_tickets_url(@ticket) }
else else
@ -38,10 +36,25 @@ class ClientTicketsController < ApplicationController
end end
end end
def respond
session[:user_ticket_respond_parent_id] = @ticket.id
@head = @ticket.head
@ticket = Ticket.new(ticket_id: @head.id,
creator: current_user,
title: @ticket.title)
if @ticket.close? or @head.close?
respond_to do |format|
format.html { redirect_to client_ticket_url(@head), alert: 'The ticket is closed' }
format.json { render json: {ticket: 'The ticket is closed'}, status: :unprocessable_entity }
end
else
render :new
end
end
# GET /tickets/1 # GET /tickets/1
# GET /tickets/1.json # GET /tickets/1.json
def show def show
prepare_comment_for @ticket
end end
# GET /tickets/new # GET /tickets/new
@ -57,10 +70,15 @@ class ClientTicketsController < ApplicationController
# POST /tickets.json # POST /tickets.json
def create def create
@ticket = Ticket.new(ticket_params) @ticket = Ticket.new(ticket_params)
if session[:user_ticket_respond_parent_id]
@head = Ticket.find(session[:user_ticket_respond_parent_id]).head
@ticket.ticket_id = @head.id
end
@ticket.creator = current_user @ticket.creator = current_user
respond_to do |format| respond_to do |format|
if @ticket.save if @ticket.save
@ticket.close_head if @ticket.close?
format.html { redirect_to client_ticket_url(@ticket), notice: 'Ticket was successfully created.' } format.html { redirect_to client_ticket_url(@ticket), notice: 'Ticket was successfully created.' }
format.json { render :show, status: :created, location: client_tickets_url(@ticket) } format.json { render :show, status: :created, location: client_tickets_url(@ticket) }
else else
@ -75,6 +93,7 @@ class ClientTicketsController < ApplicationController
def update def update
respond_to do |format| respond_to do |format|
if @ticket.update(ticket_params) if @ticket.update(ticket_params)
@ticket.close_head if @ticket.close?
format.html { redirect_to @ticket, notice: 'Ticket was successfully updated.' } format.html { redirect_to @ticket, notice: 'Ticket was successfully updated.' }
format.json { render :show, status: :ok, location: client_tickets_url(@ticket) } format.json { render :show, status: :ok, location: client_tickets_url(@ticket) }
else else
@ -97,11 +116,11 @@ class ClientTicketsController < ApplicationController
private private
# Use callbacks to share common setup or constraints between actions. # Use callbacks to share common setup or constraints between actions.
def set_ticket def set_ticket
@ticket = Ticket.find_by(id: params[:id], creator: current_user) @ticket = Ticket.find(params[:id])
@ticket = nil if not @ticket.creator == current_user and not @ticket.head.creator == current_user
@ticket @ticket
end end
# TODO: remove
def set_ticket_custom_route def set_ticket_custom_route
params[:id] = params[:client_ticket_id] params[:id] = params[:client_ticket_id]
set_ticket set_ticket
@ -113,7 +132,12 @@ class ClientTicketsController < ApplicationController
end end
def looks_ticket def looks_ticket
@ticket.set_view_by('User') if @ticket.head.head_creator_view_at.nil?
@ticket.head.update(head_creator_view_at: Time.now)
end
Ticket.where(creator: current_user, head_creator_view_at: nil, ticket: @ticket.head).each do |t|
t.update(head_creator_view_at: Time.now)
end
end end
end end

View File

@ -1,10 +1,6 @@
class ClientsController < ApplicationController class ClientsController < ApplicationController
include CommentableForm
autocomplete :contact, :name
before_action :authenticate_admin!
before_action :set_client, only: [:show, :edit, :update, :destroy] before_action :set_client, only: [:show, :edit, :update, :destroy]
before_action :authenticate_admin!
# GET /clients # GET /clients
# GET /clients.json # GET /clients.json
@ -15,7 +11,6 @@ class ClientsController < ApplicationController
# GET /clients/1 # GET /clients/1
# GET /clients/1.json # GET /clients/1.json
def show def show
prepare_comment_for @client
end end
# GET /clients/new # GET /clients/new

View File

@ -1,117 +0,0 @@
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
before_action :set_commentable, only: [:index, :about, :show, :create]
before_action :set_commentable_client, only: [:about_client, :show, :create]
# GET /comments
# GET /comments.json
def index
@comments = Comment.where(commentable: @commentable) if @commentable
@comments ||= Comment.where('0=1')
end
def about
index()
@comment = Comment.new
@comment.commentable = @commentable
render :about, layout: false
end
def about_client
index()
@comment = Comment.new
@comment.commentable = @commentable
render :about_client, layout: false
end
# GET /comments/1
# GET /comments/1.json
def show
binding.pry
render status: :forbidden unless admin_signed_in? or (user_signed_in? and @comment.commentable.is_a? Ticket and @comment.commentable.creator == current_user)
end
# GET /comments/new
def new
@comment = Comment.new
@comment.commentable = @commentable
render status: :forbidden unless admin_signed_in? or (user_signed_in? and @comment.commentable.is_a? Ticket and @comment.commentable.creator == current_user)
end
# GET /comments/1/edit
def edit
render status: :forbidden unless admin_signed_in? or (user_signed_in? and @comment.commentable.is_a? Ticket and @comment.commentable.creator == current_user)
end
# POST /comments
# POST /comments.json
def create
@comment = Comment.new(comment_params)
@comment.creator = (current_admin || current_user)
render status: :forbidden unless admin_signed_in? or (user_signed_in? and @comment.commentable.is_a? Ticket and @comment.commentable.creator == current_user)
respond_to do |format|
if @comment.save
format.html { redirect_to @comment, notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: @comment }
else
format.html { render :new }
format.json { render json: @comment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /comments/1
# PATCH/PUT /comments/1.json
def update
render status: :forbidden unless admin_signed_in?
respond_to do |format|
if @comment.update(comment_params)
format.html { redirect_to @comment, notice: 'Comment was successfully updated.' }
format.json { render :show, status: :ok, location: @comment }
else
format.html { render :edit }
format.json { render json: @comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
render status: :forbidden unless admin_signed_in?
@comment.destroy
respond_to do |format|
format.html { redirect_to comments_url, notice: 'Comment was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
@comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:title, :comment, :commentable_id, :commentable_type,
#:creator_id, :creator_type,
:role)
end
def set_commentable
return unless admin_signed_in?
@commentable ||= Client.find_by_id(params[:client_id])
@commentable ||= Contact.find_by_id(params[:contact_id])
@commentable ||= Bill.find_by_id(params[:bill_id])
@commentable ||= Ticket.find_by_id(params[:ticket_id])
@commentable_by = 'Admin'
end
def set_commentable_client
return unless user_signed_in?
if @commentable.nil?
@commentable ||= Ticket.find_by(id: params[:client_ticket_id], creator: current_user)
end
end
end

View File

@ -1,8 +0,0 @@
module CommentableForm
def prepare_comment_for(commentable)
@comment = Comment.new
@comment.commentable = commentable
end
end

View File

@ -1,8 +1,4 @@
class ContactsController < ApplicationController class ContactsController < ApplicationController
include CommentableForm
autocomplete :client, :name
before_action :set_contact, only: [:show, :edit, :update, :destroy, :view] before_action :set_contact, only: [:show, :edit, :update, :destroy, :view]
before_action :authenticate_admin! before_action :authenticate_admin!
@ -21,7 +17,6 @@ class ContactsController < ApplicationController
# GET /contacts/1 # GET /contacts/1
# GET /contacts/1.json # GET /contacts/1.json
def show def show
prepare_comment_for @contact
end end
# GET /contacts/new # GET /contacts/new
@ -74,13 +69,13 @@ class ContactsController < ApplicationController
end end
private private
# Use callbacks to share common setup or constraints between actions. # Use callbacks to share common setup or constraints between actions.
def set_contact def set_contact
@contact = Contact.find(params[:id]) @contact = Contact.find(params[:id])
end end
# Never trust parameters from the scary internet, only allow the white list through. # Never trust parameters from the scary internet, only allow the white list through.
def contact_params def contact_params
params.require(:contact).permit(:client_id, :name, :phone, :email, :note, :region, :department, :postal_code, :address) params.require(:contact).permit(:client_id, :name, :phone, :email, :note, :region, :department, :postal_code, :address)
end end
end end

View File

@ -1,19 +1,26 @@
class HomeController < ApplicationController class HomeController < ApplicationController
before_action :authenticate_admin!, only: [:admin_dashboard, :export]
before_action :authenticate_user!, only: [:user_dashboard] def index
end
def user_dashboard def user_dashboard
if not user_signed_in?
redirect_to root_url
end
@retard_bills = current_user.bills.retard.count @retard_bills = current_user.bills.retard.count
@advanced_bills = current_user.bills.advanced.count @advanced_bills = current_user.bills.advanced.count
@next_bills = current_user.bills.next.count @next_bills = current_user.bills.next.count
@old_bills = current_user.bills.old.count @old_bills = current_user.bills.old.count
@bills_count = current_user.bills.count @bills_count = current_user.bills.count
@ticket_closed = current_user.tickets.close.count @ticket_closed = current_user.tickets.heads.close.count
@ticket_opened = current_user.tickets.open.count @ticket_opened = current_user.tickets.heads.open.count
@ticket_waiting = current_user.tickets_unview.count @ticket_waiting = current_user.tickets_unview.count
end end
def admin_dashboard def admin_dashboard
if not admin_signed_in?
redirect_to root_url
end
@clients_count = Client.count @clients_count = Client.count
@contacts_count = Contact.count @contacts_count = Contact.count
@no_client_contacts_count = (Client.all.pluck(:id) - Contact.all.pluck(:client_id).uniq).size @no_client_contacts_count = (Client.all.pluck(:id) - Contact.all.pluck(:client_id).uniq).size
@ -22,16 +29,9 @@ class HomeController < ApplicationController
@next_bills = Bill.next.count @next_bills = Bill.next.count
@old_bills = Bill.old.count @old_bills = Bill.old.count
@bills_count = Bill.count @bills_count = Bill.count
@ticket_closed = Ticket.close.count @ticket_closed = Ticket.heads.close.count
@ticket_opened = Ticket.open.count @ticket_opened = Ticket.heads.open.count
@ticket_waiting = current_admin.tickets_unview.count @ticket_waiting = current_admin.tickets_unview.count
end end
def export
redirect_to "/admins/export.json" if params[:format] != "json"
@clients = Client.all
@contacts = Contact.all
@bills = Bill.all
end
end end

View File

@ -1,21 +1,19 @@
class TicketsController < ApplicationController class TicketsController < ApplicationController
include CommentableForm
before_action :set_ticket, only: [:show, :edit, :update, :destroy] before_action :set_ticket, only: [:show, :edit, :update, :destroy]
before_action :set_ticket_custom_route, only: [:close, :open] before_action :set_ticket_custom_route, only: [:close, :open, :respond]
before_action :looks_ticket, only: [:show, :edit, :update, :close, :open] before_action :looks_ticket, only: [:show, :edit, :update, :close, :open]
before_action :authenticate_admin! before_action :authenticate_admin!
# GET /tickets # GET /tickets
# GET /tickets.json # GET /tickets.json
def index def index
@tickets = Ticket.order('state DESC') @tickets = Ticket.heads.order('state DESC')
end end
def close def close
respond_to do |format| respond_to do |format|
if @ticket.close if @ticket.close
@ticket.update(admin_view_at: Time.now) # add comment ? @ticket.update(admin_view_at: Time.now)
format.html { redirect_to ticket_url(@ticket), notice: 'Ticket was successfully closed.' } format.html { redirect_to ticket_url(@ticket), notice: 'Ticket was successfully closed.' }
format.json { render :show, status: :ok, location: @ticket } format.json { render :show, status: :ok, location: @ticket }
else else
@ -28,7 +26,7 @@ class TicketsController < ApplicationController
def open def open
respond_to do |format| respond_to do |format|
if @ticket.open if @ticket.open
@ticket.update(creator_view_at: nil) # add comment ? @ticket.update(head_creator_view_at: nil)
format.html { redirect_to ticket_url(@ticket), notice: 'Ticket was successfully reopened.' } format.html { redirect_to ticket_url(@ticket), notice: 'Ticket was successfully reopened.' }
format.json { render :show, status: :ok, location: @ticket } format.json { render :show, status: :ok, location: @ticket }
else else
@ -38,10 +36,24 @@ class TicketsController < ApplicationController
end end
end end
def respond
@head = @ticket.head
@ticket = Ticket.new(ticket_id: @head.id,
creator: current_admin,
title: @ticket.title)
if @ticket.close? or @head.close?
respond_to do |format|
format.html { redirect_to ticket_url(@head), alert: 'the ticket is closed' }
format.json { render json: {ticket: 'the ticket is closed'}, status: :unprocessable_entity }
end
else
render :new
end
end
# GET /tickets/1 # GET /tickets/1
# GET /tickets/1.json # GET /tickets/1.json
def show def show
prepare_comment_for @ticket
end end
# GET /tickets/new # GET /tickets/new
@ -76,6 +88,7 @@ class TicketsController < ApplicationController
def update def update
respond_to do |format| respond_to do |format|
if @ticket.update(ticket_params) if @ticket.update(ticket_params)
@ticket.close_head if @ticket.close?
format.html { redirect_to @ticket, notice: 'Ticket was successfully updated.' } format.html { redirect_to @ticket, notice: 'Ticket was successfully updated.' }
format.json { render :show, status: :ok, location: @ticket } format.json { render :show, status: :ok, location: @ticket }
else else
@ -107,11 +120,16 @@ class TicketsController < ApplicationController
# Never trust parameters from the scary internet, only allow the white list through. # Never trust parameters from the scary internet, only allow the white list through.
def ticket_params def ticket_params
params.require(:ticket).permit(:title, :description, :state) params.require(:ticket).permit(:ticket_id, :title, :description, :state)
end end
def looks_ticket def looks_ticket
@ticket.set_view_by('Admin') if @ticket.head.admin_view_at.nil?
@ticket.head.update(admin_view_at: Time.now)
end
Ticket.where(creator: current_admin, admin_view_at: nil, ticket: @ticket.head).each do |t|
t.update(admin_view_at: Time.now)
end
end end
end end

View File

@ -1,2 +0,0 @@
module CommentsHelper
end

View File

@ -13,34 +13,4 @@ module TicketsHelper
return current_admin.tickets_unview.count return current_admin.tickets_unview.count
end end
def brize text
texts = text.split("\n")
texts.join(tag(:br))
end
def imagize text, uris
uris.each do |uri|
text.gsub!(uri, "<a href='#{uri}'><img src='#{uri}' alt='#{uri}'/></a>")
end
text
end
def linkize text, uris
uris.each do |uri|
text.gsub!(uri, "<a href='#{uri}'>#{uri}</a>")
end
text
end
def descriptionize text
uris = URI.extract(text)
imgs = uris.select{|e| e.match(/\.(jpg|png|jpeg|gif)\Z/)}
links = uris - imgs
text = raw text
text = brize text
text = imagize text, imgs
text = linkize text, links
text.html_safe
end
end end

View File

@ -9,10 +9,9 @@ class Admin < ActiveRecord::Base
#:validatable #:validatable
has_many :tickets, as: :creator has_many :tickets, as: :creator
has_many :comments, as: :creator
def tickets_unview def tickets_unview
Ticket.all.where(admin_view_at: nil) Ticket.all.heads.where(admin_view_at: nil)
end end
end end

View File

@ -1,9 +1,6 @@
class Bill < ActiveRecord::Base class Bill < ActiveRecord::Base
acts_as_commentable
belongs_to :client belongs_to :client
validates :due_date, presence: true
delegate :name, to: :client, prefix: true delegate :name, to: :client, prefix: true
scope :retard, -> {where("due_date <= '#{Date.today}'").where(paid: false)} scope :retard, -> {where("due_date <= '#{Date.today}'").where(paid: false)}

View File

@ -1,6 +1,4 @@
class Client < ActiveRecord::Base class Client < ActiveRecord::Base
acts_as_commentable
has_many :contacts has_many :contacts
has_many :bills has_many :bills
has_many :tickets, through: :user has_many :tickets, through: :user
@ -10,7 +8,7 @@ class Client < ActiveRecord::Base
delegate :name, to: :contact, allow_nil: true, prefix: true delegate :name, to: :contact, allow_nil: true, prefix: true
def last_contact def last_contact
contacts.where('view_at IS NOT NULL').pluck(:view_at).max || "never" contacts.pluck(:view_at).max || "never"
end end
def bills_retard def bills_retard

View File

@ -1,31 +0,0 @@
class Comment < ActiveRecord::Base
include ActsAsCommentable::Comment
belongs_to :commentable, :polymorphic => true
default_scope -> { order('created_at DESC') }
# NOTE: install the acts_as_votable plugin if you
# want user to vote on the quality of comments.
#acts_as_voteable
# NOTE: Comments belong to a creator
belongs_to :creator, polymorphic: true
def thread(commentable=:self)
commentable = self.commentable if commentable == :self
if commentable.nil?
[]
else
Comment.where(commentable: commentable)
end
end
after_create :update_view_date_for_ticket
def update_view_date_for_ticket
if commentable.is_a? Ticket
commentable.updated_by(creator.class.to_s)
end
end
end

View File

@ -1,5 +1,4 @@
class Contact < ActiveRecord::Base class Contact < ActiveRecord::Base
acts_as_commentable
belongs_to :client belongs_to :client
delegate :name, to: :client, prefix: true delegate :name, to: :client, prefix: true

View File

@ -1,7 +1,5 @@
# coding: utf-8 # coding: utf-8
class Ticket < ActiveRecord::Base class Ticket < ActiveRecord::Base
acts_as_commentable
# WARNING ! IT REVERSE LAST / FIRST # WARNING ! IT REVERSE LAST / FIRST
default_scope { order('created_at DESC') } default_scope { order('created_at DESC') }
@ -18,8 +16,12 @@ class Ticket < ActiveRecord::Base
belongs_to :creator, polymorphic: true belongs_to :creator, polymorphic: true
delegate :name, to: :creator, prefix: true delegate :name, to: :creator, prefix: true
scope :open, -> { where(state: OPEN) } belongs_to :ticket
scope :close, -> { where(state: CLOSE) } has_many :tickets
scope :heads, -> { where(ticket_id: nil) }
scope :open, -> { heads.where(state: OPEN) }
scope :close, -> { heads.where(state: CLOSE) }
before_save :check_creator before_save :check_creator
def check_creator def check_creator
@ -28,40 +30,39 @@ class Ticket < ActiveRecord::Base
raise ActiveRecord::RecordInvalid.new(self) raise ActiveRecord::RecordInvalid.new(self)
end end
after_create :set_view_init after_create :looks_views
def set_view_init def looks_views
set_view_by(creator_type)
end
def set_view_by(viewer_type)
if creator_type == 'Admin' if creator_type == 'Admin'
if viewer_type == 'Admin' # Entre admin pas de soucis
update(admin_view_at: Time.now, creator_view_at: Time.now) if head.creator_type == 'Admin'
update(admin_view_at: Time.now, head_creator_view_at: Time.now)
# Réponse à un client, mise a jour pour notification
else
update(admin_view_at: Time.now, head_creator_view_at: nil)
head.update(admin_view_at: Time.now, head_creator_view_at: nil)
end end
elsif creator_type == 'User' else
if viewer_type == 'User' # Reponse client, mise a jour pour notification
update(creator_view_at: Time.now) if head?
elsif viewer_type == 'Admin' update(admin_view_at: nil, head_creator_view_at: Time.now)
update(admin_view_at: Time.now) else
update(admin_view_at: nil, head_creator_view_at: Time.now)
head.update(admin_view_at: nil, head_creator_view_at: Time.now)
end end
end end
end end
def set_unview_by(viewer_type) def last_response
if creator_type == 'Admin' head.tickets.last
return # ... ?
elsif creator_type == 'User'
if viewer_type == 'User'
update(admin_view_at: nil)
elsif viewer_type == 'Admin'
update(creator_view_at: nil)
end
end
end end
def updated_by(viewer_type) def head
set_view_by(viewer_type) return self if head?
set_unview_by(viewer_type) return ticket.head
end
def head?
ticket.nil?
end end
def close def close
@ -69,7 +70,15 @@ class Ticket < ActiveRecord::Base
errors[:base] << "Already close" errors[:base] << "Already close"
return false return false
end end
update(state: Ticket::CLOSE) head.update(state: Ticket::CLOSE) && update(state: Ticket::CLOSE)
end
def close_head
if head.close?
errors[:base] << "Already close"
return false
end
head.update(state: Ticket::CLOSE)
end end
def open def open
@ -77,7 +86,7 @@ class Ticket < ActiveRecord::Base
errors[:base] << "Already open" errors[:base] << "Already open"
return false return false
end end
update(state: Ticket::OPEN) head.update(state: Ticket::OPEN) && update(state: Ticket::OPEN)
end end
def open? def open?
@ -89,7 +98,11 @@ class Ticket < ActiveRecord::Base
end end
def short_description def short_description
description.to_s.first(100) if description.size > 100
description[0..97] + "..."
else
description
end
end end
end end

View File

@ -10,19 +10,16 @@ class User < ActiveRecord::Base
has_one :client has_one :client
delegate :name, to: :client delegate :name, to: :client
has_many :tickets, as: :creator has_many :tickets, as: :creator
has_many :comments, as: :creator
has_many :contacts, through: :client has_many :contacts, through: :client
has_many :bills, through: :client has_many :bills, through: :client
after_create :create_client after_create :create_client
def create_client def create_client
if self.client_id.nil? update(client: Client.create(name: email.gsub(/@.+/, '')))
update_attributes(client: Client.create(name: email.tr('@.-_', ' ')))
end
end end
def tickets_unview def tickets_unview
tickets.where(creator_view_at: nil) tickets.heads.where(head_creator_view_at: nil)
end end
end end

View File

@ -6,38 +6,25 @@
- @bill.errors.full_messages.each do |message| - @bill.errors.full_messages.each do |message|
li = message li = message
.form-horizontal .field
.form-group = f.label :client_id
.field = f.text_field :client_id
= f.autocomplete_field :client, autocomplete_client_name_bills_path, :id_element => '#bill_client_id', class: "form-control", placeholder: "Client Name" .field
= f.label :client_id, class: "sr-only" = f.label :title
= f.text_field :client_id, class: "form-control sr-only", placeholder: "#{t('.client_id')}" = f.text_field :title
.form-group .field
.field = f.label :description
= f.label :title, class: "sr-only" = f.text_area :description
= f.text_field :title, class: "form-control", placeholder: "#{t('.title')}" .field
.form-group = f.label :amount
.field = f.number_field :amount
= f.label :description, class: "sr-only" .field
= f.text_area :description, class: "form-control", placeholder: "#{t('.description')}" = f.label :paid
.form-inline = f.check_box :paid
.form-group .field
.field = f.label :emission_date
= f.label :amount, class: "sr-only" = f.date_select :emission_date
= f.number_field :amount, class: "form-control", placeholder: "#{t('.amount')}" .field
.form-group = f.label :due_date
.field = f.date_select :due_date
= f.label t('.is_paid') .actions = f.submit
br
= f.check_box :paid, class: "form-control", placeholder: "#{t('.is_paid')}"
.form-inline
.form-group
.field
= f.label :emission_date, class: "sr-only"
= f.text_field :emission_date, class: "form-control form-date", placeholder: "#{t('.e_date')}"
.form-group
.field
= f.label :due_date, class: "sr-only"
= f.text_field :due_date, class: "form-control form-date", placeholder: "#{t('.d_date')}"
.actions = f.submit class: "btn btn-success"

View File

@ -1,6 +1,6 @@
h1.page-header = t(".page.title") h1.page-header Editing bill
== render 'form' == render 'form'
= link_to t("show"), @bill, class: 'btn btn-sm btn-default' = link_to 'Show', @bill, class: 'btn btn-sm btn-default'
= link_to t("back"), bills_path, class: 'btn btn-sm btn-default' = link_to 'Back', bills_path, class: 'btn btn-sm btn-default'

View File

@ -1,16 +1,16 @@
h1.page-header = t(".page.title") h1.page-header Listing bills
table.table.table-condensed table.table.table-condensed
thead thead
tr tr
th = t(".id") th ID
th = t(".client") th Client
th = t(".title") th Title
th = t(".description") th Description
th = t(".amount") th Amount
th = t(".paid") th Paid
th = t(".e_date") th Emission date
th = t(".d_date") th Due date
th th
th th
th th
@ -32,10 +32,10 @@ table.table.table-condensed
td.bg-danger = distance_of_time_in_words_to_now(bill.due_date) + " - " + bill.due_date.to_s(:long) td.bg-danger = distance_of_time_in_words_to_now(bill.due_date) + " - " + bill.due_date.to_s(:long)
- else - else
td.bg-info = distance_of_time_in_words_to_now(bill.due_date).to_s + " - " + bill.due_date.to_s(:long) td.bg-info = distance_of_time_in_words_to_now(bill.due_date).to_s + " - " + bill.due_date.to_s(:long)
td = link_to t('show'), bill td = link_to 'Show', bill
td = link_to t('edit'), edit_bill_path(bill) td = link_to 'Edit', edit_bill_path(bill)
td = link_to t('destroy'), bill, data: {:confirm => 'Are you sure?'}, :method => :delete td = link_to 'Destroy', bill, data: {:confirm => 'Are you sure?'}, :method => :delete
br br
= link_to t("new"), new_bill_path, class: 'btn btn-sm btn-default' = link_to 'New Bill', new_bill_path, class: 'btn btn-sm btn-default'

View File

@ -1,5 +1,5 @@
h1.page-header = t(".page.title") h1.page-header New bill
== render 'form' == render 'form'
= link_to t("back"), bills_path = link_to 'Back', bills_path

View File

@ -1,25 +1,25 @@
h1.page-header = "#{t('.page.title')}: #{@bill.title}" h1.page-header = "Bill: #{@bill.title}"
p p
strong = t ".client" strong Client:
= link_to @bill.client.name, @bill.client = link_to @bill.client.name, @bill.client
p p
strong = t ".title" strong Title:
= @bill.title = @bill.title
p p
strong = t ".description" strong Description:
= @bill.description = @bill.description
p p
strong = t ".amount" strong Amount:
= @bill.amount = @bill.amount
p p
strong = t ".is_paid" strong Paid:
= @bill.paid = @bill.paid
p p
strong = t ".e_date" strong Emission date:
= @bill.emission_date = @bill.emission_date
p p
strong = t ".d_date" strong Due date:
- if @bill.due_date < Date.today - if @bill.due_date < Date.today
- if @bill.paid - if @bill.paid
.bg-success = distance_of_time_in_words_to_now(@bill.due_date) + " - " + @bill.due_date.to_s(:long) .bg-success = distance_of_time_in_words_to_now(@bill.due_date) + " - " + @bill.due_date.to_s(:long)
@ -28,10 +28,5 @@ p
- else - else
.bg-info = distance_of_time_in_words_to_now(@bill.due_date) + " - " + @bill.due_date.to_s(:long) .bg-info = distance_of_time_in_words_to_now(@bill.due_date) + " - " + @bill.due_date.to_s(:long)
= link_to t('edit'), edit_bill_path(@bill), class: 'btn btn-sm btn-default' = link_to 'Edit', edit_bill_path(@bill), class: 'btn btn-sm btn-default'
= link_to t('back'), bills_path, class: 'btn btn-sm btn-default' = link_to 'Back', bills_path, class: 'btn btn-sm btn-default'
#comments.container-fluid
h2.page-header Comments
= render partial: "/comments/about", locals: {commentable: @bill}
= render partial: "/comments/form"

View File

@ -30,6 +30,6 @@ table.table.table-condensed
td.bg-danger = distance_of_time_in_words_to_now(bill.due_date) + " - " + bill.due_date.to_s(:long) td.bg-danger = distance_of_time_in_words_to_now(bill.due_date) + " - " + bill.due_date.to_s(:long)
- else - else
td.bg-info = distance_of_time_in_words_to_now(bill.due_date).to_s + " - " + bill.due_date.to_s(:long) td.bg-info = distance_of_time_in_words_to_now(bill.due_date).to_s + " - " + bill.due_date.to_s(:long)
td = link_to t('show'), client_bill_url(bill) td = link_to 'Show', client_bill_url(bill)
br br

View File

@ -1,4 +1,4 @@
= form_for @ticket, url: @ticket.id ? client_ticket_path(@ticket) : client_tickets_path do |f| = form_for @ticket, url: client_tickets_path do |f|
- if @ticket.errors.any? - if @ticket.errors.any?
#error_explanation #error_explanation
h2 = "#{pluralize(@ticket.errors.count, "error")} prohibited this ticket from being saved:" h2 = "#{pluralize(@ticket.errors.count, "error")} prohibited this ticket from being saved:"
@ -8,16 +8,14 @@
.form-group .form-group
.field .field
= f.label :title, class: "sr-only" = f.label :title
= f.text_field :title, class: "form-control", placeholder: "#{t('.title')}" = f.text_field :title, class: "form-control"
.form-group .form-group
.field .field
= f.label :description, class: "sr-only" = f.label :description
= f.text_area :description, class: "form-control", size: "100x8", placeholder: "#{t('.description')}" = f.text_area :description, class: "form-control", size: "100x8"
/ display the choice to close only if 'respond to' .form-group
- if @head .field
.form-group = f.label :state
.field = f.text_field :state, class: "form-control"
= f.label t('.state')
= f.select :state, ["open", "close"], {}, class: "form-control"
.actions = f.submit class: "btn btn-default" .actions = f.submit class: "btn btn-default"

View File

@ -1,6 +1,6 @@
h1.page-header = t(".page.title") h1.page-header Editing ticket
== render 'form' == render 'form'
= link_to t('show'), client_ticket_path(@ticket), class: 'btn btn-sm btn-default' = link_to 'Show', client_ticket_path(@ticket), class: 'btn btn-sm btn-default'
= link_to t('back'), client_tickets_path, class: 'btn btn-sm btn-default' = link_to 'Back', client_tickets_path, class: 'btn btn-sm btn-default'

View File

@ -3,7 +3,8 @@ h1.page-header = t ".page.title"
table.table.table-condensed table.table.table-condensed
thead thead
tr tr
th ID td ID
th = t ".creator"
th = t ".title" th = t ".title"
th = t ".description" th = t ".description"
th = t ".state" th = t ".state"
@ -12,26 +13,30 @@ table.table.table-condensed
th th
th th
th th
th
tbody tbody
- @tickets.each do |ticket| - @tickets.each do |ticket|
tr class="#{ticket.creator_view_at.nil? ? 'bg-warning' : ''}" tr class="#{ticket.head_creator_view_at.nil? ? 'bg-warning' : ''}"
td = link_to("##{ticket.id}", client_ticket_path(ticket)) td = link_to("##{ticket.id}", client_ticket_path(ticket))
td = link_to_creator(ticket)
td = link_to ticket.title, client_ticket_path(ticket) td = link_to ticket.title, client_ticket_path(ticket)
td = ticket.short_description td = ticket.tickets.empty? ? ticket.description : ticket.tickets.first.description
- if ticket.state == Ticket::CLOSE - if ticket.state == Ticket::CLOSE
td.bg-danger = t ".states.close" td.bg-danger = t ".states.close"
- else - else
td.bg-success = t ".states.open" td.bg-success = t ".states.open"
td = ticket.updated_at.to_s(:long) td = ticket.updated_at.to_s(:long)
td = ticket.comments.empty? ? "never" : distance_of_time_in_words_to_now(ticket.comments.first.updated_at) td = ticket.last_response ? distance_of_time_in_words_to_now(ticket.last_response.updated_at) : "never"
td = link_to (t "show"), ticket td = link_to (t ".buttons.show"), ticket
td = link_to (t "edit"), edit_client_ticket_path(ticket) td = link_to (t ".buttons.edit"), edit_client_ticket_path(ticket)
/ td = link_to 'Destroy', ticket, data: {:confirm => 'Are you sure?'}, :method => :delete
td = link_to (t ".buttons.respond"), client_ticket_respond_path(ticket) if ticket.open?
- if ticket.open? - if ticket.open?
td = link_to (t "close"), client_ticket_close_path(ticket), data: {:confirm => 'Are you sure?'}, :method => :patch td = link_to (t ".buttons.close"), client_ticket_close_path(ticket), data: {:confirm => 'Are you sure?'}, :method => :patch
- elsif ticket.close? - elsif ticket.close?
td = link_to (t "reopen"), client_ticket_open_path(ticket), data: {:confirm => 'Are you sure?'}, :method => :patch td = link_to (t ".buttons.reopen"), client_ticket_open_path(ticket), data: {:confirm => 'Are you sure?'}, :method => :patch
br br
= link_to (t "new"), new_client_ticket_path, class: 'btn btn-sm btn-default' = link_to (t ".buttons.new"), new_client_ticket_path, class: 'btn btn-sm btn-default'

View File

@ -1,5 +1,5 @@
h1 = @head ? t("client_tickets.response.page.title") : t(".page.title") h1 New ticket
== render 'form' == render 'form'
= link_to t('back'), client_tickets_path, class: 'btn btn-sm btn-default' = link_to 'Back', client_tickets_path

View File

@ -1,18 +1,18 @@
h1.page-header = "Ticket: #{@ticket.title}" h1.page-header = "Ticket: #{@ticket.head.title}"
p p
strong strong
| Id: # | Id: #
= @ticket.id = @ticket.id
p p
strong = t ".title" strong = t ".respond_to"
|:  |: 
= link_to @ticket.title, client_ticket_path(@ticket) = link_to @ticket.head.title, client_ticket_path(@ticket.head)
p p
strong = t ".state" strong = t ".state"
|:  |: 
- if @ticket.state == Ticket::CLOSE - if @ticket.head.state == Ticket::CLOSE
td.bg-danger = t ".states.close" td.bg-danger = t ".states.close"
- else - else
td.bg-success = t ".states.open" td.bg-success = t ".states.open"
@ -29,16 +29,40 @@ p
strong = t ".description" strong = t ".description"
|:  |: 
.container-fluid.ticket-description .container-fluid.ticket-description
= descriptionize @ticket.description = @ticket.description
== render partial: "/comments/thread", locals: {commentable: @ticket, type: 'user'} - if not @ticket.tickets.empty?
table.table.table-condensed.
thead
tr
th = t ".creator"
th = t ".title"
th = t ".description"
th = t ".state"
th = t ".last_update"
th
/ th
tbody
- @ticket.tickets.each do |ticket|
tr
td = link_to_creator(ticket)
td = link_to ticket.title, client_ticket_path(ticket)
td = ticket.short_description
- if ticket.state == Ticket::CLOSE
td.bg-danger = ticket.state
- else
td.bg-success = ticket.state
td = ticket.updated_at.to_s(:long)
td = link_to (t ".buttons.show"), client_ticket_path(ticket)
td = link_to (t ".buttons.edit"), edit_client_ticket_path(ticket)
br br
- if @ticket.open? - if @ticket.open?
= link_to (t 'close'), client_ticket_close_path(@ticket), method: :patch, class: 'btn btn-sm btn-success' = link_to (t '.buttons.respond'), client_ticket_respond_path(@ticket), class: 'btn btn-sm btn-default'
= link_to (t '.buttons.close'), client_ticket_close_path(@ticket), method: :patch, class: 'btn btn-sm btn-success'
- else - else
= link_to (t 'reopen'), client_ticket_open_path(@ticket), method: :patch, class: 'btn btn-sm btn-danger' = link_to (t '.buttons.reopen'), client_ticket_open_path(@ticket), method: :patch, class: 'btn btn-sm btn-danger'
= link_to (t 'edit'), edit_client_ticket_path(@ticket), class: 'btn btn-sm btn-default' = link_to (t '.buttons.edit'), edit_client_ticket_path(@ticket), class: 'btn btn-sm btn-default'
= link_to (t 'back'), client_tickets_path, class: 'btn btn-sm btn-default' = link_to (t '.buttons.back'), client_tickets_path, class: 'btn btn-sm btn-default'

View File

@ -6,31 +6,22 @@
- @client.errors.full_messages.each do |message| - @client.errors.full_messages.each do |message|
li = message li = message
.form-horizontal .field
.form-group = f.label :name
.field = f.text_field :name
= f.label :name, class: "sr-only" .field
= f.text_field :name, class: "form-control", placeholder: "Name" = f.label :url
.form-group = f.text_field :url
.field .field
= f.label :url, class: "sr-only" = f.label :activity
= f.text_field :url, class: "form-control", placeholder: "URL" = f.text_field :activity
.form-group .field
.field = f.label :contact_reasons
= f.label :activity, class: "sr-only" = f.text_area :contact_reasons
= f.text_field :activity, class: "form-control", placeholder: "Activity" .field
.form-group = f.label :user_id
.field = f.text_field :user_id
= f.label :contact_reasons, class: "sr-only" .field
= f.text_area :contact_reasons, class: "form-control", placeholder: "Contact reasons" = f.label :contact_id
.form-horizontal = f.text_field :contact_id
.form-group .actions = f.submit
.field
= f.label :user_id, class: "sr-only"
= f.text_field :user_id, class: "form-control", placeholder: "User ID"
.form-group
.field
= f.autocomplete_field :contact, autocomplete_contact_name_clients_path, :id_element => '#client_contact_id', class: "form-control", placeholder: "Main Contact Name"
= f.label :contact_id, class: "sr-only"
= f.text_field :contact_id, class: "form-control sr-only", placeholder: "Main Contact ID"
.actions = f.submit class: "btn btn-success"

View File

@ -1,6 +1,6 @@
h1.page-header Listing clients h1.page-header Listing clients
table.table.table-condensed table.table.table-condensed.
thead thead
tr tr
td ID td ID

View File

@ -29,58 +29,50 @@ p
= link_to 'Edit', edit_client_path(@client), class: 'btn btn-sm btn-default' = link_to 'Edit', edit_client_path(@client), class: 'btn btn-sm btn-default'
= link_to 'Back', clients_path, class: 'btn btn-sm btn-default' = link_to 'Back', clients_path, class: 'btn btn-sm btn-default'
#contacts.container-fluid table.table.table-condensed
h2 Contacts list caption Contacts list
table.table.table-condensed tr
tr th Name
th Name th Phone
th Phone th Email
th Email - @client.contacts.each do |contact|
- @client.contacts.each do |contact| tr
tr td = link_to contact.name, contact
td = link_to contact.name, contact td = contact.phone
td = contact.phone td = contact.email
td = contact.email
#bills.container-fluid table.table.table-condensed
h2 Bills list caption = "Retarded Due Bills list #{@client.bills_retard.pluck(:amount).sum} €"
table.table.table-condensed tr
caption = "Retarded Due Bills list #{@client.bills_retard.pluck(:amount).sum} €" th Title
tr th Amount
th Title th Due date
th Amount - @client.bills_retard.each do |bill|
th Due date tr
- @client.bills_retard.each do |bill| td.bg-danger = link_to bill.title, bill
tr td.bg-danger = bill.amount
td.bg-danger = link_to bill.title, bill td.bg-danger = bill.due_date
td.bg-danger = bill.amount
td.bg-danger = bill.due_date
table.table.table-condensed table.table.table-condensed
caption = "Next Bills list #{@client.bills_next.pluck(:amount).sum} €" caption = "Next Bills list #{@client.bills_next.pluck(:amount).sum} €"
tr tr
th Title th Title
th Amount th Amount
th Due date th Due date
- @client.bills_next.each do |bill| - @client.bills_next.each do |bill|
tr tr
td.bg-info = link_to bill.title, bill td.bg-info = link_to bill.title, bill
td.bg-info = bill.amount td.bg-info = bill.amount
td.bg-info = bill.due_date td.bg-info = bill.due_date
table.table.table-condensed table.table.table-condensed
caption = "Old Bills list #{@client.bills_old.pluck(:amount).sum} €" caption = "Old Bills list #{@client.bills_old.pluck(:amount).sum} €"
tr tr
th Title th Title
th Amount th Amount
th Due date th Due date
- @client.bills_old.each do |bill| - @client.bills_old.each do |bill|
tr tr
td.bg-success = link_to bill.title, bill td.bg-success = link_to bill.title, bill
td.bg-success = bill.amount td.bg-success = bill.amount
td.bg-success = bill.due_date td.bg-success = bill.due_date
#comments.container-fluid
h2.page-header Comments
= render partial: "/comments/about", locals: {commentable: @client}
= render partial: "/comments/form"

View File

@ -1,14 +0,0 @@
table.table.table-condensed
tr
th Creator
th Title
th Content
th
- commentable.comments.each do |c|
tr
td = c.creator_type
td = c.title
td = descriptionize c.comment
td
= link_to "/comments/#{c.id}.json", remote: true, data: {:confirm => 'Are you sure?'}, method: :delete, class: "close remove-comment", type: "button", "aria-label" => "Close" do
span aria-hidden="true" &times;

View File

@ -1,10 +0,0 @@
table.table.table-condensed
tr
th Creator
th Title
th Content
- commentable.comments.each do |c|
tr
td = c.creator_type
td = c.title
td = descriptionize c.comment

View File

@ -1,36 +0,0 @@
= form_for @comment, format: :json, remote: true do |f|
- if @comment.errors.any?
#error_explanation
h2 = "#{pluralize(@comment.errors.count, "error")} prohibited this comment from being saved:"
ul
- @comment.errors.full_messages.each do |message|
li = message
.form-horizontal
.form-group
.field
= f.label :title, class: "sr-only"
= f.text_field :title, class: "form-control", placeholder: "Title"
.form-group
.field
= f.label :comment, class: "sr-only"
= f.text_area :comment, class: "form-control", placeholder: "Content"
.form-inline
.field
= f.label :commentable_id, class: "form-control", class: "sr-only hidden"
= f.number_field :commentable_id, class: "form-control hidden", placeholder: "Commentable ID"
.field
= f.label :commentable_type, class: "sr-only hidden"
= f.text_field :commentable_type, class: "form-control hidden", placeholder: "Commentable Type"
.form-inline
.field
= f.label :creator_id, class: "sr-only"
= f.number_field :creator_id, class: "form-control hidden", placeholder: "Creator ID"
.field
= f.label :creator_type, class: "sr-only hidden"
= f.text_field :creator_type, class: "form-control hidden", placeholder: "Creator Type"
.form-inline
.field
= f.label :role, class: "sr-only hidden"
= f.text_field :role, class: "form-control hidden", placeholder: "Role"
.actions = f.submit class: "btn btn-success action-comment"

View File

@ -1,4 +0,0 @@
#comments.container-fluid
h2.page-header Comments
= render partial: "/comments/form"
= render partial: "/comments/about#{type == 'user' ? '_client' : '' }", locals: {commentable: commentable}

View File

@ -1 +0,0 @@
== render partial: 'thread', locals: {commentable: @commentable, type: 'admin'}

View File

@ -1 +0,0 @@
== render partial: 'thread', locals: {commentable: @commentable, type: 'user'}

View File

@ -1,7 +0,0 @@
h1.page-header Editing comment
== render 'form'
= link_to t('show'), @comment
'|
= link_to t('back'), comments_path

View File

@ -1,33 +0,0 @@
h1 Listing comments
table.table.table-condensed
thead
tr
th Title
th Comment
th Commentable
th Commentable type
th Creator ID
th Creator Type
th Role
th
th
th
tbody
- @comments.each do |comment|
tr
td = comment.title
td = comment.comment
td = comment.commentable_id
td = comment.commentable_type
td = comment.creator_id
td = comment.creator_type
td = comment.role
td = link_to t('show'), comment
td = link_to t('edit'), edit_comment_path(comment)
td = link_to t('destroy'), comment, data: {:confirm => 'Are you sure?'}, :method => :delete
br
= link_to t('new'), new_comment_path

View File

@ -1,4 +0,0 @@
json.array!(@comments) do |comment|
json.extract! comment, :id, :title, :comment, :commentable_id, :commentable_type, :creator_id, :creator_type, :role
json.url comment_url(comment, format: :json)
end

View File

@ -1,5 +0,0 @@
h1.page-header New comment
== render 'form'
= link_to t('back'), comments_path

View File

@ -1,27 +0,0 @@
p#notice = notice
p
strong Title:
= @comment.title
p
strong Comment:
= @comment.comment
p
strong Commentable:
= @comment.commentable_id
p
strong Commentable type:
= @comment.commentable_type
p
strong Creator id:
= @comment.creator_id
p
strong Creator type:
= @comment.creator_type
p
strong Role:
= @comment.role
= link_to t('edit'), edit_comment_path(@comment)
'|
= link_to t('back'), comments_path

View File

@ -1 +0,0 @@
json.extract! @comment, :id, :title, :comment, :commentable_id, :commentable_type, :creator_id, :creator_type, :role, :created_at, :updated_at

View File

@ -6,49 +6,34 @@
- @contact.errors.full_messages.each do |message| - @contact.errors.full_messages.each do |message|
li = message li = message
.form-horizontal .field
.form-group = f.label :client_id
.field = f.text_field :client_id
= f.autocomplete_field :client, autocomplete_client_name_contacts_path, :id_element => '#contact_client_id', class: "form-control", placeholder: "Client Name" .field
= f.label :client_id, class: "sr-only" = f.label :name
= f.text_field :client_id, class: "form-control sr-only", placeholder: "Client ID" = f.text_field :name
.form-inline .field
.form-group = f.label :phone
.field = f.text_field :phone
= f.label :name, class: "sr-only" .field
= f.text_field :name, class: "form-control", placeholder: "Name" = f.label :email
.form-group = f.text_field :email
.field .field
= f.label :phone, class: "sr-only" = f.label :view_at
= f.text_field :phone, class: "form-control", placeholder: "Phone" = f.date_select :view_at
.form-group .field
.field = f.label :note
= f.label :email, class: "sr-only" = f.text_area :note
= f.text_field :email, class: "form-control", placeholder: "Email" .field
.form-inline = f.label :region
.form-group = f.text_field :region
.field .field
= f.label :region, class: "sr-only" = f.label :department
= f.text_field :region, class: "form-control", placeholder: "Region" = f.text_field :department
.form-group .field
.field = f.label :postal_code
= f.label :department, class: "sr-only" = f.text_field :postal_code
= f.text_field :department, class: "form-control", placeholder: "Department" .field
.form-group = f.label :address
.field = f.text_area :address
= f.label :postal_code, class: "sr-only" .actions = f.submit
= f.text_field :postal_code, class: "form-control", placeholder: "Postal Code"
.form-horizontal
.form-group
.field
= f.label :address, class: "sr-only"
= f.text_area :address, class: "form-control", placeholder: "Address"
.form-group
.field
= f.label :note, class: "sr-only"
= f.text_area :note, class: "form-control", placeholder: "Note"
.form-group
.field
= f.label :view_at, class: "sr-only"
= f.text_field :view_at, class: "form-control form-date", placeholder: "View at"
.actions = f.submit class: "btn btn-success"

View File

@ -14,7 +14,7 @@ p
= @contact.email = @contact.email
p p
strong View at: strong View at:
= @contact.view_at = @contact.last_contact
p p
strong Note: strong Note:
= @contact.note = @contact.note
@ -33,8 +33,3 @@ p
= link_to 'Edit', edit_contact_path(@contact), class: 'btn btn-sm btn-default' = link_to 'Edit', edit_contact_path(@contact), class: 'btn btn-sm btn-default'
= link_to 'Back', contacts_path, class: 'btn btn-sm btn-default' = link_to 'Back', contacts_path, class: 'btn btn-sm btn-default'
#comments.container-fluid
h2.page-header Comments
= render partial: "/comments/about", locals: {commentable: @contact}
= render partial: "/comments/form"

View File

@ -1,14 +1,14 @@
h1.page-header = t ".title" h1.page-header Admin Dashboard
.row.placeholders .row.placeholders
.col-xs-6.col-sm-2.placeholder .col-xs-6.col-sm-3.placeholder
= link_to clients_url do = link_to clients_url do
= image_tag "icone_client.png", alt: "image clients", class: "img-responsive", size: "128x128" = image_tag "icone_client.png", alt: "image clients", class: "img-responsive", size: "128x128"
h4 Clients h4 Clients
span.text-muted = "Count: #{@clients_count}" span.text-muted = "Count: #{@clients_count}"
br br
.col-xs-6.col-sm-2.placeholder .col-xs-6.col-sm-3.placeholder
= link_to contacts_url do = link_to contacts_url do
= image_tag "icone_contact.png", alt: "image contact", class: "img-responsive", size: "128x128" = image_tag "icone_contact.png", alt: "image contact", class: "img-responsive", size: "128x128"
h4 Contacts h4 Contacts
@ -17,7 +17,7 @@ h1.page-header = t ".title"
span.text-muted = "Client with no contacts: #{@no_client_contacts_count}" span.text-muted = "Client with no contacts: #{@no_client_contacts_count}"
br br
.col-xs-6.col-sm-2.placeholder .col-xs-6.col-sm-3.placeholder
= link_to bills_url do = link_to bills_url do
= image_tag "icone_bill.png", alt: "image bills", class: "img-responsive", size: "128x128" = image_tag "icone_bill.png", alt: "image bills", class: "img-responsive", size: "128x128"
h4 Bills h4 Bills
@ -32,7 +32,7 @@ h1.page-header = t ".title"
span.text-muted = "Total Bills: #{@bills_count}" span.text-muted = "Total Bills: #{@bills_count}"
br br
.col-xs-6.col-sm-2.placeholder .col-xs-6.col-sm-3.placeholder
= link_to tickets_url do = link_to tickets_url do
= image_tag "icone_ticket.png", alt: "image tickets", class: "img-responsive", size: "128x128" = image_tag "icone_ticket.png", alt: "image tickets", class: "img-responsive", size: "128x128"
h4 Tickets h4 Tickets
@ -43,16 +43,4 @@ h1.page-header = t ".title"
span.text-muted = "Waiting tickets: #{@ticket_waiting}" span.text-muted = "Waiting tickets: #{@ticket_waiting}"
br br
.col-xs-6.col-sm-2.placeholder
= link_to admins_export_url do
= image_tag "icone_export.png", alt: "image export", class: "img-responsive", size: "128x128"
h4
abbr[title="This option only export the clients, contacts, and bills, without comments etc. If you want to export the complete database, use the native feature of your ORDBMS."] Export
span.text-muted = "Clients: #{@clients_count}"
br
span.text-muted = "Contacts: #{@contacts_count}"
br
span.text-muted = "Bills: #{@bills_count}"
br
/ here, add a wonderful statistic graph with js / here, add a wonderful statistic graph with js

View File

@ -1,3 +0,0 @@
json.clients(@clients)
json.contacts(@contacts)
json.bills(@bills)

View File

@ -3,18 +3,18 @@
.space-client.col-xs-4 .space-client.col-xs-4
.panel.panel-success .panel.panel-success
.panel-heading .panel-heading
h3 = t "home.user_dashboard.title" h3 = t ".client.title"
.panel-body .panel-body
- if user_signed_in? - if user_signed_in?
= link_to t(".links.logout"), destroy_user_session_path, method: :delete = link_to t(".client.links.logout"), destroy_user_session_path, method: :delete
- else - else
= link_to t(".links.login"), new_user_session_path = link_to t(".client.links.login"), new_user_session_path
.space-admin.col-xs-4 .space-admin.col-xs-4
.panel.panel-danger .panel.panel-danger
.panel-heading .panel-heading
h3 = t("home.admin_dashboard.title") h3 = t(".admin.title")
.panel-body .panel-body
- if admin_signed_in? - if admin_signed_in?
= link_to t(".links.logout"), destroy_admin_session_path, method: :delete = link_to t(".admin.links.logout"), destroy_admin_session_path, method: :delete
- else - else
= link_to t(".links.login"), new_admin_session_path = link_to t(".admin.links.login"), new_admin_session_path

View File

@ -1,28 +1,28 @@
h1.page-header = t ".title" h1.page-header User Dashboard
.row.placeholders .row.placeholders
.col-xs-6.col-sm-3.placeholder .col-xs-6.col-sm-3.placeholder
= link_to client_bills_url do = link_to client_bills_url do
= image_tag "icone_bill.png", alt: "image bills", class: "img-responsive", size: "128x128" = image_tag "icone_bill.png", alt: "image bills", class: "img-responsive", size: "128x128"
h4 = t "home.dashboard.bills" h4 Bills
span.text-muted = "#{t 'home.dashboard.retard_bills'}: #{@retard_bills}" span.text-muted = "Retard bills: #{@retard_bills}"
br br
span.text-muted = "#{t 'home.dashboard.advanced_bills'}: #{@advanced_bills}" span.text-muted = "Advanced bills: #{@advanced_bills}"
br br
span.text-muted = "#{t 'home.dashboard.next_bills'}: #{@retard_bills}" span.text-muted = "Next bills: #{@retard_bills}"
br br
span.text-muted = "#{t 'home.dashboard.old_bills'}: #{@old_bills}" span.text-muted = "Old bills: #{@old_bills}"
br br
span.text-muted = "#{t 'home.dashboard.total_bills'}: #{@bills_count}" span.text-muted = "Total Bills: #{@bills_count}"
br br
.col-xs-6.col-sm-3.placeholder .col-xs-6.col-sm-3.placeholder
= link_to client_tickets_url do = link_to client_tickets_url do
= image_tag "icone_ticket.png", alt: "image tickets", class: "img-responsive", size: "128x128" = image_tag "icone_ticket.png", alt: "image tickets", class: "img-responsive", size: "128x128"
h4 = t "home.dashboard.tickets" h4 Tickets
span.text-muted = "#{t 'home.dashboard.closed_tickets'}: #{@ticket_closed}" span.text-muted = "Closed tickets: #{@ticket_closed}"
br br
span.text-muted = "#{t 'home.dashboard.opened_tickets'}: #{@ticket_opened}" span.text-muted = "Opened tickets: #{@ticket_opened}"
br br
span.text-muted = "#{t 'home.dashboard.waiting_tickets'}: #{@ticket_waiting}" span.text-muted = "Waiting tickets: #{@ticket_waiting}"
br br

View File

@ -12,11 +12,11 @@ nav.navbar.navbar-inverse.navbar-fixed-top
#navbar.navbar-collapse.collapse #navbar.navbar-collapse.collapse
ul.nav.navbar-nav.navbar-right ul.nav.navbar-nav.navbar-right
- if user_signed_in? - if user_signed_in?
li = link_to t(".user_dashboard"), users_dashboard_url li = link_to "User Dashboard", users_dashboard_url
- if admin_signed_in? - if admin_signed_in?
li = link_to t(".admin_dashboard"), admins_dashboard_url li = link_to "Admin Dashboard", admins_dashboard_url
- if user_signed_in? - if user_signed_in?
li = link_to "#{current_user.name} #{t '.logout'}", destroy_user_session_path, method: :delete li = link_to "#{current_user.name} logout", destroy_user_session_path, method: :delete
- if admin_signed_in? - if admin_signed_in?
li = link_to "#{current_admin.email} #{t '.logout'}", destroy_admin_session_path, method: :delete li = link_to "#{current_admin.email} logout", destroy_admin_session_path, method: :delete
li = link_to "Help", help_url li = link_to "Help", help_url

View File

@ -4,13 +4,13 @@
ul.nav.nav-sidebar ul.nav.nav-sidebar
li.active li.active
= link_to users_dashboard_url do = link_to users_dashboard_url do
= t ".user.user" | User
span.sr-only (current) span.sr-only (current)
li = link_to client_bills_url do li = link_to client_bills_url do
= t ".user.bills_due" | bills due 
.badge = user_bills_count_due .badge = user_bills_count_due
li = link_to client_tickets_url do li = link_to client_tickets_url do
= t ".user.tickets" | tickets 
.badge = user_tickets_unview_count .badge = user_tickets_unview_count
/ Admin side / Admin side
@ -20,11 +20,11 @@
ul.nav.nav-sidebar ul.nav.nav-sidebar
li.active li.active
= link_to admins_dashboard_url do = link_to admins_dashboard_url do
= t(".admin.admin") | Admin
span.sr-only (current) span.sr-only (current)
li = link_to t(".admin.clients"), clients_url li = link_to "clients", clients_url
li = link_to t(".admin.contacts"), contacts_url li = link_to "contacts", contacts_url
li = link_to t( ".admin.bills"), bills_url li = link_to "bills", bills_url
li = link_to tickets_url do li = link_to tickets_url do
= t ".admin.tickets" | tickets 
.badge = admin_tickets_unview_count .badge = admin_tickets_unview_count

View File

@ -6,25 +6,22 @@
- @ticket.errors.full_messages.each do |message| - @ticket.errors.full_messages.each do |message|
li = message li = message
.form-horizontal .field
.form-group = f.label :ticket_id
.field = f.text_field :ticket_id
= f.label :creator_type, class: "sr-only" .field
= f.text_field :creator_type, class: "form-control", placeholder: "Creator type" = f.label :creator_type
.form-group = f.text_field :creator_type
.field .field
= f.label :creator_id, class: "sr-only" = f.label :creator_id
= f.text_field :creator_id, class: "form-control", placeholder: "Creator ID" = f.text_field :creator_id
.form-group .field
.field = f.label :title
= f.label :title, class: "sr-only" = f.text_field :title
= f.text_field :title, class: "form-control", placeholder: "Title" .field
.form-group = f.label :description
.field = f.text_area :description
= f.label :description, class: "sr-only" .field
= f.text_area :description, class: "form-control", placeholder: "Description" = f.label :state
.form-group = f.text_field :state
.field .actions = f.submit
= f.label :state, class: "sr-only"
= f.select :state, ["open", "close"], {}, class: "form-control"
.actions = f.submit class: "btn btn-success"

View File

@ -14,6 +14,7 @@ table.table.table-condensed.
th th
th th
th th
th
tbody tbody
- @tickets.each do |ticket| - @tickets.each do |ticket|
@ -21,16 +22,17 @@ table.table.table-condensed.
td = link_to("##{ticket.id}", ticket) td = link_to("##{ticket.id}", ticket)
td = link_to_creator(ticket) td = link_to_creator(ticket)
td = link_to ticket.title, ticket td = link_to ticket.title, ticket
td = ticket.short_description td = ticket.tickets.empty? ? ticket.description : ticket.tickets.first.description
- if ticket.state == Ticket::CLOSE - if ticket.state == Ticket::CLOSE
td.bg-danger = ticket.state td.bg-danger = ticket.state
- else - else
td.bg-success = ticket.state td.bg-success = ticket.state
td = ticket.updated_at.to_s(:long) td = ticket.updated_at.to_s(:long)
td = ticket.comments.empty? ? "never" : distance_of_time_in_words_to_now(ticket.comments.first.updated_at) td = ticket.last_response ? distance_of_time_in_words_to_now(ticket.last_response.updated_at) : "never"
td = link_to 'Show', ticket td = link_to 'Show', ticket
td = link_to 'Edit', edit_ticket_path(ticket) td = link_to 'Edit', edit_ticket_path(ticket)
td = link_to 'Destroy', ticket, data: {:confirm => 'Are you sure?'}, :method => :delete td = link_to 'Destroy', ticket, data: {:confirm => 'Are you sure?'}, :method => :delete
td = link_to 'Respond', ticket_respond_path(ticket) if ticket.open?
- if ticket.open? - if ticket.open?
td = link_to 'Close', ticket_close_path(ticket), data: {:confirm => 'Are you sure?'}, :method => :patch td = link_to 'Close', ticket_close_path(ticket), data: {:confirm => 'Are you sure?'}, :method => :patch
- elsif ticket.close? - elsif ticket.close?

View File

@ -1,16 +1,19 @@
h1.page-header = "Show ticket: #{@ticket.title}" h1.page-header = "Show ticket: #{@ticket.head.title}"
p p
strong strong
| Id: # | Id: #
= @ticket.id = @ticket.id
p
strong Réponse à:
= link_to @ticket.head.title, @ticket.head
p p
strong State: strong State:
- if @ticket.state == Ticket::CLOSE - if @ticket.head.state == Ticket::CLOSE
td.bg-danger = @ticket.state td.bg-danger = @ticket.head.state
- else - else
td.bg-success = @ticket.state td.bg-success = @ticket.head.state
p p
strong Creator: strong Creator:
@ -20,19 +23,43 @@ p
= @ticket.title = @ticket.title
p p
strong Description: strong Description:
.container-fluid.ticket-description = @ticket.description
= descriptionize @ticket.description
p p
strong State: strong State:
= @ticket.state = @ticket.state
table.table.table-condensed.
thead
tr
th Creator
th Title
th Description
th Last update
th
th
th
tbody
- @ticket.tickets.each do |ticket|
tr
td = link_to_creator(ticket)
td = link_to ticket.title, ticket
td = ticket.description
- if ticket.state == Ticket::CLOSE
td.bg-danger = ticket.state
- else
td.bg-success = ticket.state
td = ticket.updated_at.to_s(:long)
td = link_to 'Show', ticket
td = link_to 'Edit', edit_ticket_path(ticket)
td = link_to 'Destroy', ticket, data: {:confirm => 'Are you sure?'}, :method => :delete
br br
- if @ticket.open? - if @ticket.open?
= link_to 'Respond', ticket_respond_path(@ticket), class: 'btn btn-sm btn-default'
= link_to 'Close', ticket_close_path(@ticket), method: :patch, class: 'btn btn-sm btn-success' = link_to 'Close', ticket_close_path(@ticket), method: :patch, class: 'btn btn-sm btn-success'
- else - else
= link_to 'Reopen', ticket_open_path(@ticket), method: :patch, class: 'btn btn-sm btn-danger' = link_to 'Reopen', ticket_open_path(@ticket), method: :patch, class: 'btn btn-sm btn-danger'
= link_to 'Edit', edit_ticket_path(@ticket), class: 'btn btn-sm btn-default' = link_to 'Edit', edit_ticket_path(@ticket), class: 'btn btn-sm btn-default'
= link_to 'Back', tickets_path, class: 'btn btn-sm btn-default' = link_to 'Back', tickets_path, class: 'btn btn-sm btn-default'
== render partial: "/comments/thread", locals: {commentable: @ticket, type: 'admin'}

View File

@ -1,3 +1,3 @@
# Be sure to restart your server when you modify this file. # Be sure to restart your server when you modify this file.
Rails.application.config.session_store :cookie_store, key: '_MorningPeak_session' Rails.application.config.session_store :cookie_store, key: '_WebImmo_session'

View File

@ -1,77 +0,0 @@
fr:
bills:
form:
client_id: ID du Client
title: Titre
description: Détail
amount: Montant
is_paid: Payé ?
e_date: "Date d'emission"
d_date: "Date d'échéance"
edit:
page:
title: Éditer une facture
new:
page:
title: Nouvelle facture
index:
page:
title: Liste des factures
id: ID
client: Client
Title: Titre
description: Detail
amount: Montant
is_paid: Payé ?
e_date: "Date d'emission"
d_date: "Date d'échéance"
show:
page:
title: Facture
id: ID
client: Client
Title: Titre
description: Detail
amount: Montant
is_paid: Payé ?
e_date: "Date d'emission"
d_date: "Date d'échéance"
en:
bills:
form:
client_id: Client ID
title: Title
description: Description
amount: Amount
is_paid: Paid ?
e_date: Emission date
d_date: Due date
edit:
page:
title: Edit a Bill
new:
page:
title: New Bill
index:
page:
title: Listing Bills
id: ID
client: Client
title: Title
description: Description
amount: Amount
is_paid: Paid ?
e_date: Emission date
d_date: Due date
show:
page:
title: Bill
id: ID
client: Client
title: Title
description: Description
amount: Amount
is_paid: Paid ?
e_date: Emission date
d_date: Due date

View File

@ -1,9 +1,5 @@
fr: fr:
client_tickets: client_tickets:
form:
title: Titre
description: Détail
state: État
show: show:
title: Titre title: Titre
respond_to: Réponse à respond_to: Réponse à
@ -13,6 +9,14 @@ fr:
open: Ouvert open: Ouvert
creator: Créateur creator: Créateur
description: Description description: Description
buttons:
show: Afficher
edit: Éditer
respond: Répondre
close: Fermer
reopen: Ré-ouvrir
new: Créer un nouveau Ticket
back: "Revenir à l'index"
page: page:
title: Afficher un Ticket title: Afficher un Ticket
index: index:
@ -26,24 +30,18 @@ fr:
description: Description description: Description
last_update: Dernière mise à jour last_update: Dernière mise à jour
last_response: Dernière réponse last_response: Dernière réponse
buttons:
show: Afficher
edit: Éditer
respond: Répondre
close: Fermer
reopen: Ré-ouvrir
new: Créer un nouveau Ticket
page: page:
title: Liste de mes Tickets title: Liste de mes Tickets
edit:
page:
title: Éditer un Ticket
new:
page:
title: Nouveau Ticket
response:
page:
title: Répondre au Ticket
en: en:
client_tickets: client_tickets:
form:
title: Title
description: Description
state: State
show: show:
title: Title title: Title
respond_to: Repond to respond_to: Repond to
@ -53,6 +51,14 @@ en:
open: Ouvert open: Ouvert
creator: Créateur creator: Créateur
description: Description description: Description
buttons:
show: Show
edit: Edit
respond: Repond
close: Close
reopen: Reopen
new: New Ticket
back: Back
page: page:
title: Afficher un Ticket title: Afficher un Ticket
index: index:
@ -66,14 +72,12 @@ en:
description: Description description: Description
last_update: Last update last_update: Last update
last_response: Last Response last_response: Last Response
buttons:
show: Show
edit: Edit
respond: Repond
close: Close
reopen: Reopen
new: New Ticket
page: page:
title: My Tickets list title: My Tickets list
new:
page:
title: New Ticket
edit:
page:
title: Edition Ticket
response:
page:
title: Response to Ticket

View File

@ -1,5 +0,0 @@
fr:
clients:
en:
clients:

View File

@ -1,5 +0,0 @@
fr:
contacts:
en:
contacts:

View File

@ -1,44 +1,29 @@
fr: fr:
home: home:
user_dashboard:
title: Mon Espace Client
admin_dashboard:
title: Espace Administrateur
dashboard:
bills: Factures
tickets: Demandes
retard_bills: Factures en retard
advanced_bills: Factures payé à l'avance
next_bills: Prochaines factures
old_bills: Anciennes factures
total_bills: Toutes les factures
closed_tickets: Tickets clos
opened_tickets: Tickets ouverts
waiting_tickets: Tickets en attente
index: index:
links: client:
login: Se connecter title: Espace Client
logout: Se déconnecter links:
login: Se connecter
logout: Se déconnecter
admin:
title: Espace Admin
links:
login: Se connecter
logout: Se déconnecter
en: en:
home: home:
user_dashboard:
title: Client Dashboard
admin_dashboard:
title: Admin Dashboard
dashboard:
bills: Bills
tickets: Tickets
retard_bills: Retarded Bills
advanced_bills: Advanced Bills
next_bills: Next due Bills
old_bills: Old paid Bills
total_bills: Total Bills
closed_tickets: Closed Tickets
opened_tickets: Opened Tickets
waiting_tickets: Waiting Tickets
index: index:
links: client:
login: Sign in title: Client Dashboard
logout: Sign out links:
login: Sign in
logout: Sign out
admin:
title: Admin Dashboard
links:
login: Sign in
logout: Sign out

View File

@ -1,35 +0,0 @@
fr:
layouts:
sidebar:
user:
user: Client
bills_due: Factures dûes
tickets: Demandes
admin:
admin: Administrateur
clients: Clients
contacts: Contacts
bills: Factures
tickets: Demandes
navbar:
user_dashboard: Mon Espace Client
admin_dashboard: Espace Administrateur
logout: Déconnecter
en:
layouts:
sidebar:
user:
user: Client
bills_due: Due Bills
tickets: Tickets
admin:
admin: Administrator
clients: Clients
contacts: Contacts
bills: Bills
tickets: Tickets
navbar:
user_dashboard: Client Dashboard
admin_dashboard: Administrator Dashboard
logout: Logout

View File

@ -2,8 +2,4 @@ fr:
show: Afficher show: Afficher
back: Retour back: Retour
edit: Editer edit: Editer
new: Nouveau
delete: Supprimer delete: Supprimer
respond: Répondre
close: Fermer
reopen: Ré-ouvrir

View File

@ -1,5 +0,0 @@
fr:
tickets:
en:
tickets:

View File

@ -2,69 +2,85 @@ Rails.application.routes.draw do
root to: "home#index" root to: "home#index"
match "/help", to: "home#help", via: [:get], as: 'help' match "/help", to: "home#help", via: [:get], as: 'help'
resources :comments # ADMINISTRATION
# ----- ADMINISTRATION -----
resources :tickets do resources :tickets do
patch :close patch :close # TODO: for now, argument is ticket_id instead of id. How to change that ?
patch :open patch :open
resources :comments do get :respond
collection do
get 'about'
end
end
end end
# path '/tickets/:id/close', to: 'tickets#close', as: 'close_ticket'
# get '/tickets/:id/respond', to: 'tickets#respond', as: 'respond_ticket'
resources :contacts
resources :contacts do
get :autocomplete_client_name, :on => :collection
resources :comments do
collection do
get 'about'
end
end
end
match '/contacts/:id/view', to: 'contacts#view', via: [:patch, :get], as: 'view_contact' match '/contacts/:id/view', to: 'contacts#view', via: [:patch, :get], as: 'view_contact'
resources :bills
resources :clients
resources :bills do
get :autocomplete_client_name, :on => :collection
resources :comments do
collection do
get 'about'
end
end
end
resources :clients do
get :autocomplete_contact_name, :on => :collection
resources :comments do
collection do
get 'about'
end
end
end
# ----- DASHBOARDS -----
match "/users/dashboard", to: 'home#user_dashboard', via: [:get], as: 'users_dashboard'
match "/users", to: redirect('/users/dashboard'), via: [:get]
devise_for :users devise_for :users
match "/users/dashboard", to: 'home#user_dashboard', via: [:get], as: 'users_dashboard'
match "/admins/dashboard", to: 'home#admin_dashboard', via: [:get], as: 'admins_dashboard'
match "/admins", to: redirect('/admins/dashboard'), via: [:get]
match "/admins/export", to: "home#export", via: [:get], as: 'admins_export'
devise_for :admins devise_for :admins
match "/admins/dashboard", to: 'home#admin_dashboard', via: [:get], as: 'admins_dashboard'
# ----- CLIENTS ----- # CLIENTS
resources :client_tickets, path: '/client/tickets' do resources :client_tickets, path: '/client/tickets' do
patch :close patch :close
patch :open patch :open
resources :comments do get :respond
collection do
get 'about', to: 'comments#about_client'
end
end
end end
resources :client_bills, path: '/client/bills' resources :client_bills, path: '/client/bills'
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
# root 'welcome#index'
# Example of regular route:
# get 'products/:id' => 'catalog#view'
# Example of named route that can be invoked with purchase_url(id: product.id)
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
# Example resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Example resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Example resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Example resource route with more complex sub-resources:
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', on: :collection
# end
# end
# Example resource route with concerns:
# concern :toggleable do
# post 'toggle'
# end
# resources :posts, concerns: :toggleable
# resources :photos, concerns: :toggleable
# Example resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
end end

View File

@ -7,8 +7,8 @@ class CreateBills < ActiveRecord::Migration
t.text :description t.text :description
t.integer :amount t.integer :amount
t.boolean :paid, default: false, null: false t.boolean :paid, default: false, null: false
t.date :emission_date, null: false, default: Date.today t.date :emission_date
t.date :due_date, null: false t.date :due_date
t.timestamps null: false t.timestamps null: false
end end

View File

@ -1,17 +0,0 @@
class CreateComments < ActiveRecord::Migration
def self.up
create_table :comments do |t|
t.string :title, :limit => 50, :default => ""
t.text :comment
t.references :commentable, :polymorphic => true, :index => true
t.references :creator, :polymorphic => true, :index => true
t.string :role, :default => "comments", :index => true
t.timestamps
end
end
def self.down
drop_table :comments
end
end

View File

@ -1,8 +0,0 @@
class UpdateTickets < ActiveRecord::Migration
def change
rename_column :tickets, :head_creator_view_at, :creator_view_at
remove_column :tickets, :ticket_id
end
end

View File

@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160131000119) do ActiveRecord::Schema.define(version: 20150718140959) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -37,14 +37,14 @@ ActiveRecord::Schema.define(version: 20160131000119) do
create_table "bills", force: :cascade do |t| create_table "bills", force: :cascade do |t|
t.integer "client_id" t.integer "client_id"
t.string "title", null: false t.string "title", null: false
t.text "description" t.text "description"
t.integer "amount" t.integer "amount"
t.boolean "paid", default: false, null: false t.boolean "paid", default: false, null: false
t.date "emission_date", default: '2016-01-30', null: false t.date "emission_date"
t.date "due_date", null: false t.date "due_date"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end end
add_index "bills", ["client_id"], name: "index_bills_on_client_id", using: :btree add_index "bills", ["client_id"], name: "index_bills_on_client_id", using: :btree
@ -60,22 +60,6 @@ ActiveRecord::Schema.define(version: 20160131000119) do
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end end
create_table "comments", force: :cascade do |t|
t.string "title", limit: 50, default: ""
t.text "comment"
t.integer "commentable_id"
t.string "commentable_type"
t.integer "creator_id"
t.string "creator_type"
t.string "role", default: "comments"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "comments", ["commentable_type", "commentable_id"], name: "index_comments_on_commentable_type_and_commentable_id", using: :btree
add_index "comments", ["creator_type", "creator_id"], name: "index_comments_on_creator_type_and_creator_id", using: :btree
add_index "comments", ["role"], name: "index_comments_on_role", using: :btree
create_table "contacts", force: :cascade do |t| create_table "contacts", force: :cascade do |t|
t.integer "client_id" t.integer "client_id"
t.string "name" t.string "name"
@ -96,16 +80,18 @@ ActiveRecord::Schema.define(version: 20160131000119) do
create_table "tickets", force: :cascade do |t| create_table "tickets", force: :cascade do |t|
t.integer "creator_id" t.integer "creator_id"
t.string "creator_type" t.string "creator_type"
t.integer "ticket_id"
t.string "title" t.string "title"
t.text "description" t.text "description"
t.string "state", default: "open", null: false t.string "state", default: "open", null: false
t.time "admin_view_at" t.time "admin_view_at"
t.time "creator_view_at" t.time "head_creator_view_at"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end end
add_index "tickets", ["creator_type", "creator_id"], name: "index_tickets_on_creator_type_and_creator_id", using: :btree add_index "tickets", ["creator_type", "creator_id"], name: "index_tickets_on_creator_type_and_creator_id", using: :btree
add_index "tickets", ["ticket_id"], name: "index_tickets_on_ticket_id", using: :btree
create_table "users", force: :cascade do |t| create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false t.string "email", default: "", null: false
@ -127,4 +113,5 @@ ActiveRecord::Schema.define(version: 20160131000119) do
add_foreign_key "bills", "clients" add_foreign_key "bills", "clients"
add_foreign_key "contacts", "clients" add_foreign_key "contacts", "clients"
add_foreign_key "tickets", "tickets"
end end

View File

@ -1,16 +1,16 @@
# coding: utf-8 # coding: utf-8
u1 = Admin.create(email: "admin@admin.admin", password: 'adminadmin') u1 = Admin.create(email: "admin@wir.com", password: 'wir2015')
u2 = User.create(email: "user@client.com", password: 'user2015') u2 = User.create(email: "admin@jerevedunemaison.com", password: 'jrdm2015')
u3 = User.create(email: "user@rasecampagneimmo.com", password: 'rci2015') u3 = User.create(email: "admin@rasecampagneimmo.com", password: 'rci2015')
c2=u2.client c2=u2.client
c3=u3.client c3=u3.client
co1=Contact.create(name: "Ceric Trovic", client: c2) co1=Contact.create(name: "Eric Chatry", client: c2)
co2=Contact.create(name: "M. Sometime", client: c3) co2=Contact.create(name: "M. Sometime", client: c3)
co3=Contact.create(name: "Mme. Chose", client: c3) co3=Contact.create(name: "Mme. Chose", client: c3)
c2.update(name: "CLIENT", contact: co1) c2.update(name: "JRDM", contact: co1)
c3.update(name: "RaseCampagneImmo") c3.update(name: "RaseCampagneImmo")

9
doc.sh
View File

@ -1,9 +1,2 @@
#!/bin/sh #!/bin/sh
if [[ $(bundle list erd) == "" ]] erd --polymorphism --inheritance --attributes=content
then
echo "ERD Not found, installation ..."
gem install rails-erd
fi
bundle exec erd --polymorphism --inheritance --attributes=content
xdg-open erd.pdf

View File

@ -1,49 +0,0 @@
require 'test_helper'
class CommentsControllerTest < ActionController::TestCase
setup do
@comment = comments(:one)
end
test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:comments)
end
test "should get new" do
get :new
assert_response :success
end
test "should create comment" do
assert_difference('Comment.count') do
post :create, comment: { comment: @comment.comment, commentable_id: @comment.commentable_id, commentable_type: @comment.commentable_type, role: @comment.role, title: @comment.title, user_id: @comment.user_id }
end
assert_redirected_to comment_path(assigns(:comment))
end
test "should show comment" do
get :show, id: @comment
assert_response :success
end
test "should get edit" do
get :edit, id: @comment
assert_response :success
end
test "should update comment" do
patch :update, id: @comment, comment: { comment: @comment.comment, commentable_id: @comment.commentable_id, commentable_type: @comment.commentable_type, role: @comment.role, title: @comment.title, user_id: @comment.user_id }
assert_redirected_to comment_path(assigns(:comment))
end
test "should destroy comment" do
assert_difference('Comment.count', -1) do
delete :destroy, id: @comment
end
assert_redirected_to comments_path
end
end

View File

@ -18,7 +18,7 @@ class ContactsControllerTest < ActionController::TestCase
test "should create contact" do test "should create contact" do
assert_difference('Contact.count') do assert_difference('Contact.count') do
post :create, contact: { address: @contact.address, client_id: @contact.client_id, department: @contact.department, email: @contact.email, view_at: @contact.view_at, name: @contact.name, note: @contact.note, phone: @contact.phone, postal_code: @contact.postal_code, region: @contact.region } post :create, contact: { address: @contact.address, client_id: @contact.client_id, department: @contact.department, email: @contact.email, last_contact: @contact.last_contact, name: @contact.name, note: @contact.note, phone: @contact.phone, postal_code: @contact.postal_code, region: @contact.region }
end end
assert_redirected_to contact_path(assigns(:contact)) assert_redirected_to contact_path(assigns(:contact))
@ -35,7 +35,7 @@ class ContactsControllerTest < ActionController::TestCase
end end
test "should update contact" do test "should update contact" do
patch :update, id: @contact, contact: { address: @contact.address, client_id: @contact.client_id, department: @contact.department, email: @contact.email, view_at: @contact.view_at, name: @contact.name, note: @contact.note, phone: @contact.phone, postal_code: @contact.postal_code, region: @contact.region } patch :update, id: @contact, contact: { address: @contact.address, client_id: @contact.client_id, department: @contact.department, email: @contact.email, last_contact: @contact.last_contact, name: @contact.name, note: @contact.note, phone: @contact.phone, postal_code: @contact.postal_code, region: @contact.region }
assert_redirected_to contact_path(assigns(:contact)) assert_redirected_to contact_path(assigns(:contact))
end end