From 6431ec9e647e7f3a7bdd75faa0bd14b0495e3804 Mon Sep 17 00:00:00 2001 From: Nicolas VARROT Date: Thu, 17 Mar 2016 16:21:28 +0100 Subject: [PATCH] Need Images added + Devis attached to devis + text fixing + mail triggers + bug fix --- app/assets/stylesheets/public.scss | 11 ++++ app/assets/stylesheets/public/need.scss | 21 ++++++- .../admin/contact_messages_controller.rb | 5 +- app/controllers/admin/customers_controller.rb | 2 +- app/controllers/admin/documents_controller.rb | 4 ++ app/controllers/admin/needs_controller.rb | 7 ++- app/controllers/application_controller.rb | 3 + .../public/contact_messages_controller.rb | 10 ++- .../public/customers_auths_controller.rb | 5 +- .../public/customers_controller.rb | 6 +- .../public/documents_controller.rb | 14 ++++- app/controllers/public/messages_controller.rb | 8 +++ .../public/my_account_controller.rb | 4 +- app/controllers/public/needs_controller.rb | 33 ++++++++-- app/controllers/public/offers_controller.rb | 10 +++ app/mailers/admin_mailer.rb | 48 +++++++++++++++ app/mailers/customer_mailer.rb | 55 +++++++++++++++-- app/models/admin.rb | 4 +- app/models/customer.rb | 2 +- app/models/need.rb | 14 +++-- app/uploaders/devis_uploader.rb | 5 +- app/views/admin/needs/_form.html.haml | 8 ++- app/views/admin/needs/_need.html.haml | 5 ++ .../admin/needs/_need_to_validate.html.haml | 3 + app/views/admin/needs/index.html.haml | 4 ++ .../customer_accept_offer.html.haml | 7 +++ .../customer_disinterested.html.haml | 7 +++ .../customer_download_document.html.haml | 9 +++ .../customer_interested.html.haml | 7 +++ .../customer_post_comment.html.haml | 10 +++ .../customer_send_contact_message.html.haml | 8 +++ .../customer_upload_document.html.haml | 9 +++ .../contact_message_received.html.haml | 8 +++ .../document_available.html.haml | 13 ++++ .../document_verified.html.haml | 12 ++++ .../customer_mailer/need_commented.html.haml | 10 +++ .../customer_mailer/need_negociated.html.haml | 10 +++ .../need_negociation_failed.html.haml | 8 +++ .../customer_mailer/offer_accepted.html.haml | 7 +++ app/views/layouts/public.html.haml | 58 +++++++++--------- app/views/public/customers_auths/new.haml | 4 +- app/views/public/needs/_form.html.haml | 3 + app/views/public/needs/_need_item.html.haml | 13 ++-- app/views/public/needs/show.html.haml | 29 +++++---- config/routes.rb | 2 + ...160317130441_add_image_and_file_to_need.rb | 6 ++ db/schema.rb | 19 +++--- public/placeholder.png | Bin 0 -> 6909 bytes 48 files changed, 454 insertions(+), 96 deletions(-) create mode 100644 app/views/admin_mailer/customer_accept_offer.html.haml create mode 100644 app/views/admin_mailer/customer_disinterested.html.haml create mode 100644 app/views/admin_mailer/customer_download_document.html.haml create mode 100644 app/views/admin_mailer/customer_interested.html.haml create mode 100644 app/views/admin_mailer/customer_post_comment.html.haml create mode 100644 app/views/admin_mailer/customer_send_contact_message.html.haml create mode 100644 app/views/admin_mailer/customer_upload_document.html.haml create mode 100644 app/views/customer_mailer/contact_message_received.html.haml create mode 100644 app/views/customer_mailer/document_available.html.haml create mode 100644 app/views/customer_mailer/document_verified.html.haml create mode 100644 app/views/customer_mailer/need_commented.html.haml create mode 100644 app/views/customer_mailer/need_negociated.html.haml create mode 100644 app/views/customer_mailer/need_negociation_failed.html.haml create mode 100644 app/views/customer_mailer/offer_accepted.html.haml create mode 100644 db/migrate/20160317130441_add_image_and_file_to_need.rb create mode 100644 public/placeholder.png diff --git a/app/assets/stylesheets/public.scss b/app/assets/stylesheets/public.scss index b3df104..cd0ffb9 100755 --- a/app/assets/stylesheets/public.scss +++ b/app/assets/stylesheets/public.scss @@ -644,6 +644,17 @@ height: 100%; margin:20px auto; display:block; height:200px; + margin-bottom:60px; + +} +#big-logo{ + + margin:20px auto; + width:400px; + height:400px; + display:block; + + } diff --git a/app/assets/stylesheets/public/need.scss b/app/assets/stylesheets/public/need.scss index f774563..9c3ab74 100755 --- a/app/assets/stylesheets/public/need.scss +++ b/app/assets/stylesheets/public/need.scss @@ -115,14 +115,31 @@ .need-item{ - height: 150px; + height: 200px; background-color:#fff; padding-top:30px; position:relative; + padding-left:190px; + .need-image{ + margin-top:26px; + position: absolute; + top:0px; + left:0px; + width:174px; + height:174px; + background-color: rgb(163, 159, 159); + background-size: cover; + background-position: center center; + background-image: url('/placeholder.png'); + } p.description{ font-size:12px; color:rgb(163, 159, 159); + max-height: 105px; + word-wrap: break-word; + text-overflow: ellipsis; + overflow: hidden; } p.info{ @@ -157,7 +174,7 @@ position:absolute; left:0px; bottom:0px; - padding-left:5px; + padding-left:180px; padding-bottom:5px; .item{ display:inline; diff --git a/app/controllers/admin/contact_messages_controller.rb b/app/controllers/admin/contact_messages_controller.rb index bcd7b1a..bf702f6 100755 --- a/app/controllers/admin/contact_messages_controller.rb +++ b/app/controllers/admin/contact_messages_controller.rb @@ -11,10 +11,11 @@ class Admin::ContactMessagesController < ApplicationController @contact_message.read_by_admin = true if @contact_message.save - flash[:notice] = "Commentaire envoyé." + CustomerMailer.contact_message_received(@contact_message.contact, @contact_message).deliver + flash[:notice] = "Message envoyé." return redirect_to :back else - flash[:error] = "Votre commentaire n'a pas pu être envoyé." + flash[:error] = "Votre message n'a pas pu être envoyé." return render 'index' end diff --git a/app/controllers/admin/customers_controller.rb b/app/controllers/admin/customers_controller.rb index e5523fc..9a6eb87 100755 --- a/app/controllers/admin/customers_controller.rb +++ b/app/controllers/admin/customers_controller.rb @@ -29,7 +29,7 @@ class Admin::CustomersController < ApplicationController @customer.account_validated = true @customer.account_validated_at = Time.now @customer.save - CustomerMailer.delay.validate_account(@customer) + CustomerMailer.validate_account(@customer).deliver redirect_to :back end diff --git a/app/controllers/admin/documents_controller.rb b/app/controllers/admin/documents_controller.rb index 388085d..c2dde86 100755 --- a/app/controllers/admin/documents_controller.rb +++ b/app/controllers/admin/documents_controller.rb @@ -25,6 +25,9 @@ class Admin::DocumentsController < ApplicationController @document.document = params[:document] if @document.save @document.state = :document_available + + CustomerMailer.document_available(@accepted_offer.customer, @document).deliver + if @document.returned_document? @document.remove_returned_document! end @@ -130,6 +133,7 @@ class Admin::DocumentsController < ApplicationController if @document.save + CustomerMailer.document_verified(@accepted_offer.customer, @document).deliver flash[:success] = "Document vérifié" else flash[:error] = "Impossible vérifier le document" diff --git a/app/controllers/admin/needs_controller.rb b/app/controllers/admin/needs_controller.rb index d99982d..c66d072 100755 --- a/app/controllers/admin/needs_controller.rb +++ b/app/controllers/admin/needs_controller.rb @@ -66,6 +66,11 @@ class Admin::NeedsController < ApplicationController @comments = @need.messages.order(created_at: :desc).page params[:page] end + def download_devis + @need = Need.find(params[:need_id]) + send_file @need.devis.file.path, :filename => "devis-need-#{@need.id}.#{@need.devis.file.extension}" + end + def create @need = Need.new(need_params) @@ -160,7 +165,7 @@ class Admin::NeedsController < ApplicationController private def need_params - params.require(:need).permit(:title, :description, :category_id, :author_id) + params.require(:need).permit(:title, :image_file_id, :description, :category_id, :author_id) end def build_category_tree diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 60c2a77..81bf302 100755 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -3,7 +3,10 @@ class ApplicationController < ActionController::Base # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception + + def auth_customer + session[:devise_id] = params[:d] if params[:d] if !current_customer session[:before_auth_url] = request.url diff --git a/app/controllers/public/contact_messages_controller.rb b/app/controllers/public/contact_messages_controller.rb index 78bfcdb..33b417b 100755 --- a/app/controllers/public/contact_messages_controller.rb +++ b/app/controllers/public/contact_messages_controller.rb @@ -20,10 +20,16 @@ class Public::ContactMessagesController < ApplicationController @contact_message.read_by_customer = true if @contact_message.save - flash[:notice] = "Commentaire envoyé." + flash[:notice] = "Message envoyé." + + admins = Admin.where.not(email: nil) + admins.each do |admin| + AdminMailer.customer_send_contact_message(admin, @contact_message).deliver + end + return redirect_to :back else - flash[:error] = "Votre commentaire n'a pas pu être envoyé." + flash[:error] = "Votre message n'a pas pu être envoyé." return render 'index' end diff --git a/app/controllers/public/customers_auths_controller.rb b/app/controllers/public/customers_auths_controller.rb index 4767c56..13d98c1 100755 --- a/app/controllers/public/customers_auths_controller.rb +++ b/app/controllers/public/customers_auths_controller.rb @@ -3,6 +3,7 @@ class Public::CustomersAuthsController < ApplicationController layout "public" def new + @biglogo = true @no_search = true params[:step] = "login" if params[:for_annonce] @@ -26,7 +27,7 @@ class Public::CustomersAuthsController < ApplicationController end def create - + @biglogo = true @customer = Customer.new() if cookies[:mlm_token] and @parent = Customer.find_parrain(cookies[:mlm_token]) @customer.parent_code = @parent.mlm_token.upcase @@ -54,7 +55,7 @@ class Public::CustomersAuthsController < ApplicationController redirect_to :root else flash.now.alert = "Email ou mot de passe incorect" - + render :action => "new" end end diff --git a/app/controllers/public/customers_controller.rb b/app/controllers/public/customers_controller.rb index 061e947..838aed7 100755 --- a/app/controllers/public/customers_controller.rb +++ b/app/controllers/public/customers_controller.rb @@ -63,8 +63,8 @@ class Public::CustomersController < ApplicationController @customer = Customer.new(params.require(:customer).permit!) if @customer.save - CustomerMailer.delay.confirm(@customer) - CustomerMailer.delay.notify_ins(@customer) + CustomerMailer.confirm(@customer).deliver + CustomerMailer.notify_ins(@customer).deliver @customer.authenticate(params[:password]) @@ -89,7 +89,7 @@ class Public::CustomersController < ApplicationController @customer.enabled = true @customer.save(:validate => false) - CustomerMailer.delay.confirm_ins(@customer) + CustomerMailer.confirm_ins(@customer).deliver cookies[:customer_auth_token] = @customer.token diff --git a/app/controllers/public/documents_controller.rb b/app/controllers/public/documents_controller.rb index 5b1fadb..2537aed 100644 --- a/app/controllers/public/documents_controller.rb +++ b/app/controllers/public/documents_controller.rb @@ -13,9 +13,14 @@ class Public::DocumentsController < ApplicationController def download @document = @accepted_offer.documents.find(params[:id]) - if @document.state == :document_available + if @document.state == 'document_available' @document.state = :document_downloaded @document.save + + admins = Admin.where.not(email: nil) + admins.each do |admin| + AdminMailer.customer_download_document(admin, @document, current_customer).deliver + end end send_file @document.document.file.path @@ -51,7 +56,12 @@ class Public::DocumentsController < ApplicationController @document = @accepted_offer.documents.find(params[:id]) @document.returned_document = params[:returned_document] if @document.save - @document.return_document! + @document.state = :document_returned + @document.save + admins = Admin.where.not(email: nil) + admins.each do |admin| + AdminMailer.customer_upload_document(admin, @document, current_customer).deliver + end flash[:success] = "Document chargé" else flash[:error] = "Impossible de charger le document" diff --git a/app/controllers/public/messages_controller.rb b/app/controllers/public/messages_controller.rb index 81620d6..4cb0824 100755 --- a/app/controllers/public/messages_controller.rb +++ b/app/controllers/public/messages_controller.rb @@ -15,6 +15,14 @@ class Public::MessagesController < ApplicationController if(@message.save) flash[:notice] = "Commentaire envoyé." + admins = Admin.where.not(email: nil) + admins.each do |admin| + AdminMailer.customer_post_comment(admin, @need, @message).deliver + end + + @need.customers.each do |customer| + CustomerMailer.need_commented(customer, @need, @message).deliver + end else flash[:error] = "Votre commentaire n'a pas pu être envoyé." end diff --git a/app/controllers/public/my_account_controller.rb b/app/controllers/public/my_account_controller.rb index 0129906..5a7c25b 100755 --- a/app/controllers/public/my_account_controller.rb +++ b/app/controllers/public/my_account_controller.rb @@ -6,7 +6,7 @@ class Public::MyAccountController < ApplicationController def index @accepted_offers = current_customer.accepted_offers.order(created_at: :desc).page(params[:page_offers]).per(5) - + @wishes = current_customer.needs.shared.page(params[:page_wishes]).per(5) @needs = Kaminari.paginate_array(current_customer.owned_needs.order(created_at: :desc)) @@ -45,7 +45,7 @@ class Public::MyAccountController < ApplicationController def reconfirm @no_search = true - CustomerMailer.delay.confirm(current_customer) + CustomerMailer.confirm(current_customer).deliver redirect_to public_my_account_path, :notice => "Le mail vous a été renvoyé" end diff --git a/app/controllers/public/needs_controller.rb b/app/controllers/public/needs_controller.rb index a5e65ed..2e6d27c 100755 --- a/app/controllers/public/needs_controller.rb +++ b/app/controllers/public/needs_controller.rb @@ -66,6 +66,19 @@ class Public::NeedsController < ApplicationController end + + def download_devis + @need = Need.find(params[:need_id]) + + if @need.author.id != current_customer.id + flash[:error] = "Vous n'êtes pas le propriétaire" + return redirect_to :back + end + + send_file @need.devis.file.path, filename: "devis-need-#{@need.id}.#{@need.devis.file.extension}" + end + + def new @need = Need.new() end @@ -101,10 +114,13 @@ class Public::NeedsController < ApplicationController def create @need = Need.new(need_params) @need.author = current_customer + if !@need.devis? + flash[:error] = "Vous devez joindre un devis au format PDF" + return render :action => "new" + end + if @need.save flash[:notice] = "Votre besoin à été créé avec succès." - - redirect_to public_my_account_path else render :action => "new" @@ -115,13 +131,22 @@ class Public::NeedsController < ApplicationController def wish @need = Need.find(params[:id]) - + admins = Admin.where.not(email: nil) if (!@need.customers.include?(current_customer)) @need.customers << current_customer flash[:notice] = "Vous avez signalé votre intérêt pour ce besoin" + # Find all admins with email + + admins.each do |admin| + AdminMailer.customer_interested(admin, @need, current_customer).deliver + end + else @need.customers.delete(current_customer) flash[:error] = "Vous n'êtes maintenant plus intéressé par ce besoin" + admins.each do |admin| + AdminMailer.customer_disinterested(admin, @need, current_customer).deliver + end end redirect_to :back end @@ -133,7 +158,7 @@ class Public::NeedsController < ApplicationController end def need_params - params.require(:need).permit(:title, :description, :category_id) + params.require(:need).permit(:title, :devis, :description, :category_id) end def check_owner diff --git a/app/controllers/public/offers_controller.rb b/app/controllers/public/offers_controller.rb index a58cf70..b34f70b 100755 --- a/app/controllers/public/offers_controller.rb +++ b/app/controllers/public/offers_controller.rb @@ -18,7 +18,17 @@ class Public::OffersController < ApplicationController @accepted_offer.documents << @document if @accepted_offer.save + admins = Admin.where.not(email: nil) + admins.each do |admin| + AdminMailer.customer_accept_offer(admin, @accepted_offer).deliver + end + + CustomerMailer.offer_accepted(current_customer, @accepted_offer).deliver + flash[:notice] = "Proposition acceptée avec succès !" + + + redirect_back_or_default :root end end diff --git a/app/mailers/admin_mailer.rb b/app/mailers/admin_mailer.rb index b098f00..35812e3 100755 --- a/app/mailers/admin_mailer.rb +++ b/app/mailers/admin_mailer.rb @@ -10,4 +10,52 @@ class AdminMailer < ApplicationMailer @need = need mail to: admin.email, subject: "Nouvelle proposition de besoin" end + + # a faire + def customer_interested(admin, need, customer) + @need = need + @customer = customer + mail to: admin.email, subject: "Un client s'est intéressé à un besoin" + end + + # a faire + def customer_disinterested(admin, need, customer) + @need = need + @customer = customer + mail to: admin.email, subject: "Un client s'est désintéressé d'un besoin" + end + + # a faire + def customer_post_comment(admin, need, comment) + @need = need + @comment = comment + mail to: admin.email, subject: "Un client a laissé un commentaire sur un besoin" + end + + # a faire + def customer_accept_offer(admin, accepted_offer) + @accepted_offer = accepted_offer + mail to: admin.email, subject: "Un client a accepté une offre" + end + + # a faire + def customer_download_document(admin, document, customer) + @document = document + @customer = customer + mail to: admin.email, subject: "Un client a téléchargé un document" + end + + # a faire + def customer_upload_document(admin, document, customer) + @document = document + mail to: admin.email, subject: "Un client a renvoyé un document" + end + + # a faire + def customer_send_contact_message(admin, contact_message) + @contact_message = contact_message + mail to: admin.email, subject: "Un client a envoyé un message de contact" + end + + end diff --git a/app/mailers/customer_mailer.rb b/app/mailers/customer_mailer.rb index f0c94e1..62d7a43 100755 --- a/app/mailers/customer_mailer.rb +++ b/app/mailers/customer_mailer.rb @@ -50,19 +50,66 @@ class CustomerMailer < ApplicationMailer def negociate_need(need, customer) @need = need @customer = customer - mail to: @customer.email, :subject => "Négociation en cours !" + mail to: @customer.email, :subject => "Négociation en cours pour le besoin #{@need.title}" end + + def need_negociated(customer ,need) + @need = need + @customer = customer + mail to: @customer.email, :subject => "Besoin #{@need.title} négocié !" + end + + + def need_negociation_failed(customer, need) + @need = need + @customer = customer + mail to: @customer.email, :subject => "Négociation échouée pour le besoin #{@need.title}" + end + + def need_commented(customer, need, comment) + @need = need + @customer = customer + @comment = comment + mail to: @customer.email, :subject => "Nouveau commentaire pour le besoin #{@need.title}" + end + + + def offer_accepted(customer, accepted_offer) + @accepted_offer = accepted_offer + @customer = customer + mail to: @customer.email, :subject => "Vous avez accepté une proposition" + end + + + def document_available(customer, document) + @document = document + @customer = customer + mail to: @customer.email, :subject => "Document disponible pour la proposition #{@document.accepted_offer.offer.need.title}" + end + + + def document_verified(customer, document) + @document = document + @customer = customer + mail to: @customer.email, :subject => "Document vérifié pour la proposition #{@document.accepted_offer.offer.need.title}" + end + + + def contact_message_received(customer, contact_message) + @contact_message = contact_message + @customer = customer + mail to: @customer.email, :subject => "Message reçu" + end + + def new_user(customer) @customer = customer @parent = @customer.parent if @parent #mail from: "no-reply@negos.pro", to: @parent.email, :subject => "Vous avez un nouvel affilié sur Negos.pro !" do |format| # format.html { render layout: false } - - #end - end end diff --git a/app/models/admin.rb b/app/models/admin.rb index e41ff59..2cdcb81 100755 --- a/app/models/admin.rb +++ b/app/models/admin.rb @@ -30,13 +30,13 @@ class Admin < ActiveRecord::Base generate_token(:reset_password_token) self.reset_password_sent_at = Time.now save! - AdminMailer.delay.password_reset(self) + AdminMailer.password_reset(self).deliver end def fullname "#{firstname.capitalize} #{name.upcase}" end - + def generate_token(column) begin self[column] = SecureRandom.urlsafe_base64 diff --git a/app/models/customer.rb b/app/models/customer.rb index 22b56e7..40fb2a8 100755 --- a/app/models/customer.rb +++ b/app/models/customer.rb @@ -183,7 +183,7 @@ class Customer < ActiveRecord::Base self.save(:validate => false) - CustomerMailer.delay.password_reset(self) + CustomerMailer.password_reset(self).deliver end diff --git a/app/models/need.rb b/app/models/need.rb index f22d5a7..cfd5d41 100755 --- a/app/models/need.rb +++ b/app/models/need.rb @@ -30,12 +30,14 @@ class Need < ActiveRecord::Base has_many :customers, -> { uniq }, through: :wishes has_many :messages, dependent: :destroy has_many :offers, dependent: :destroy + belongs_to :image_file belongs_to :category, class_name: "NeedCategory" validates :title, :presence => true, length: {within: 4..128} validates :description, presence: true, length: {maximum: 65535} belongs_to :author, class_name: 'Customer' + mount_uploader :devis, DevisUploader # Need's workflow lifecycle workflow do @@ -60,41 +62,41 @@ class Need < ActiveRecord::Base # Find all admins with email admins = Admin.where.not(email: nil) admins.each do |admin| - AdminMailer.delay.new_need(admin, self) + AdminMailer.new_need(admin, self).deliver end end end def validate if self.author - CustomerMailer.delay.validate_need(self) + CustomerMailer.validate_need(self).deliver end end def negociate customers = self.customers customers.each do |customer| - CustomerMailer.delay.negociate_need(self, customer) + CustomerMailer.negociate_need(self, customer).deliver end end def accept customers = self.customers customers.each do |customer| - CustomerMailer.delay.accept_need(self, customer) + CustomerMailer.need_negociated(customer, self).deliver end end def reject customers = self.customers customers.each do |customer| - CustomerMailer.delay.reject_need(self, customer) + CustomerMailer.need_negociation_failed(customer, self).deliver end end def refuse if self.author - CustomerMailer.delay.refuse_need(self) + CustomerMailer.refuse_need(self).deliver end end diff --git a/app/uploaders/devis_uploader.rb b/app/uploaders/devis_uploader.rb index aad367b..f1d11e0 100755 --- a/app/uploaders/devis_uploader.rb +++ b/app/uploaders/devis_uploader.rb @@ -6,7 +6,7 @@ class DevisUploader < CarrierWave::Uploader::Base def filename - "Devis-#{model.offer.need.title}-pour-#{model.customer.organisation}.#{file.extension}" if original_filename.present? + "devis.#{file.extension}" if original_filename.present? end def store_dir @@ -17,8 +17,5 @@ class DevisUploader < CarrierWave::Uploader::Base %w(pdf) end - def url - download_admin_offer_accepted_offer_path(model.offer, model) - end end diff --git a/app/views/admin/needs/_form.html.haml b/app/views/admin/needs/_form.html.haml index 08be0de..843cbe2 100755 --- a/app/views/admin/needs/_form.html.haml +++ b/app/views/admin/needs/_form.html.haml @@ -9,8 +9,10 @@ =f.input :title, :label => "Titre : " =f.input :category, include_blank: "Toute catégorie", :as => :select, :collection => @tree.map{|c| [(c.level > 0 ? ('   ' * (c.level - 1)) + "|- ": "").html_safe + c.name, c.id]}, label: "Catégorie de besoin" =f.input :description, :label => "Description : ", :rows => 5, :input_html => {:style => "height:100px;"} + =f.input :image_file_id, :label => "Image", :as => :qi_image_select =f.input :author, :label => "Auteur", include_blank: "Administrateur" - =f.input :created_at, :label => "Créé le", disabled: true - =f.input :updated_at, :label => "Dernière modification le", disabled: true - .actions= f.submit "Sauvegarder", :class => "btn btn-primary" + .actions + -if @need.devis? + = link_to ic(:download) + " Télécharger le devis attaché par l'émetteur", admin_need_download_devis_path(@need), class: "btn btn-default" + = f.submit "Sauvegarder", :class => "btn btn-primary" diff --git a/app/views/admin/needs/_need.html.haml b/app/views/admin/needs/_need.html.haml index 2a82bfc..6309b64 100755 --- a/app/views/admin/needs/_need.html.haml +++ b/app/views/admin/needs/_need.html.haml @@ -4,6 +4,11 @@ %tr{:id => need.id, class: css_class} %td =link_to need.title, edit_admin_need_path(need) + %td + -if need.image_file + =link_to "Oui", need.image_file.file.url, target: "_blank" + -else + Non %td -if need.category =link_to need.category.name, edit_admin_need_category_path(need.category) diff --git a/app/views/admin/needs/_need_to_validate.html.haml b/app/views/admin/needs/_need_to_validate.html.haml index 2b924bb..b891800 100755 --- a/app/views/admin/needs/_need_to_validate.html.haml +++ b/app/views/admin/needs/_need_to_validate.html.haml @@ -13,6 +13,9 @@ Administrateur %td Il y a #{time_ago_in_words( need.created_at)} + %td + -if need.devis? + =link_to ic(:download) + " Offre/Devis", admin_need_download_devis_path(need), class: "btn btn-primary btn-sm" %td.actions{:style => "width:150px;text-align:right"} -if(need.created?) diff --git a/app/views/admin/needs/index.html.haml b/app/views/admin/needs/index.html.haml index ad7234c..d4e81f7 100755 --- a/app/views/admin/needs/index.html.haml +++ b/app/views/admin/needs/index.html.haml @@ -24,6 +24,8 @@ Émetteur %th Créé + %th + Dévis/Offre %th{:style => "width:100px"}   @@ -45,6 +47,8 @@ %tr %th Titre + %th + Image? %th Catégorie diff --git a/app/views/admin_mailer/customer_accept_offer.html.haml b/app/views/admin_mailer/customer_accept_offer.html.haml new file mode 100644 index 0000000..b1e89cb --- /dev/null +++ b/app/views/admin_mailer/customer_accept_offer.html.haml @@ -0,0 +1,7 @@ +%p Bonjour, + +%p + Le client + %strong= @accepted_offer.customer.fullname + vient d'accepter la proposition concernant le besoin + %strong= @accepted_offer.offer.need.title diff --git a/app/views/admin_mailer/customer_disinterested.html.haml b/app/views/admin_mailer/customer_disinterested.html.haml new file mode 100644 index 0000000..9ae8f0e --- /dev/null +++ b/app/views/admin_mailer/customer_disinterested.html.haml @@ -0,0 +1,7 @@ +%p Bonjour, + +%p + Le client + %strong= @customer.fullname + vient de supprimer son intérêt pour le besoin + %strong= @need.title diff --git a/app/views/admin_mailer/customer_download_document.html.haml b/app/views/admin_mailer/customer_download_document.html.haml new file mode 100644 index 0000000..1193a37 --- /dev/null +++ b/app/views/admin_mailer/customer_download_document.html.haml @@ -0,0 +1,9 @@ +%p Bonjour, + +%p + Le client + %strong= @customer.fullname + vient de télécharger le document + %strong= @document.title + concernant le besoin + %strong= @document.accepted_offer.offer.need.title diff --git a/app/views/admin_mailer/customer_interested.html.haml b/app/views/admin_mailer/customer_interested.html.haml new file mode 100644 index 0000000..470f955 --- /dev/null +++ b/app/views/admin_mailer/customer_interested.html.haml @@ -0,0 +1,7 @@ +%p Bonjour, + +%p + Le client + %strong= @customer.fullname + vient de signaler son intérêt pour le besoin + %strong= @need.title diff --git a/app/views/admin_mailer/customer_post_comment.html.haml b/app/views/admin_mailer/customer_post_comment.html.haml new file mode 100644 index 0000000..35a1d3c --- /dev/null +++ b/app/views/admin_mailer/customer_post_comment.html.haml @@ -0,0 +1,10 @@ +%p Bonjour, + +%p + Un client a laissé un commentaire sur le besoin + %strong= @need.title + +%p + %strong= @comment.customer.fullname + +%p= @comment.content diff --git a/app/views/admin_mailer/customer_send_contact_message.html.haml b/app/views/admin_mailer/customer_send_contact_message.html.haml new file mode 100644 index 0000000..a31893d --- /dev/null +++ b/app/views/admin_mailer/customer_send_contact_message.html.haml @@ -0,0 +1,8 @@ +%p Bonjour, + +%p Un client vient de vous envoyer un message de contact. Pour répondre, merci de vous connecter à l'interface administrateur. + +%p + %strong= @contact_message.customer.fullname + +%p= @contact_message.content diff --git a/app/views/admin_mailer/customer_upload_document.html.haml b/app/views/admin_mailer/customer_upload_document.html.haml new file mode 100644 index 0000000..cb5b3f1 --- /dev/null +++ b/app/views/admin_mailer/customer_upload_document.html.haml @@ -0,0 +1,9 @@ +%p Bonjour, + +%p + Le client + %strong= @customer.fullname + vient de retourner le document + %strong= @document.title + concernant le besoin + %strong= @document.accepted_offer.offer.need.title diff --git a/app/views/customer_mailer/contact_message_received.html.haml b/app/views/customer_mailer/contact_message_received.html.haml new file mode 100644 index 0000000..50d3a0e --- /dev/null +++ b/app/views/customer_mailer/contact_message_received.html.haml @@ -0,0 +1,8 @@ +%p Bonjour, + +%p Un administrateur Négos vient de répondre à votre message. Pour répondre, connectez-vous à votre espace perso depuis le site. + +%p + %strong= @contact_message.admin.author_name + +%p= @contact_message.content diff --git a/app/views/customer_mailer/document_available.html.haml b/app/views/customer_mailer/document_available.html.haml new file mode 100644 index 0000000..4b21ce1 --- /dev/null +++ b/app/views/customer_mailer/document_available.html.haml @@ -0,0 +1,13 @@ +%p Bonjour, + +%p + Un document est disponible pour une proposition que vous avez récemment acceptée: + %strong= @document.accepted_offer.offer.need.title + +%p + Le titre du document concerné est + %strong= @document.title + +%p Rendez-vous dans votre espace perso afin de télécharger ce document et nous le retourner complété. + +%p Merci diff --git a/app/views/customer_mailer/document_verified.html.haml b/app/views/customer_mailer/document_verified.html.haml new file mode 100644 index 0000000..37e1303 --- /dev/null +++ b/app/views/customer_mailer/document_verified.html.haml @@ -0,0 +1,12 @@ +%p Bonjour, + +%p + Un document que vous nous avez récemment retourné pour la proposition + %strong= @document.accepted_offer.offer.need.title + vient d'être vérifié + +%p + Le titre du document concerné est + %strong= @document.title + +%p Merci diff --git a/app/views/customer_mailer/need_commented.html.haml b/app/views/customer_mailer/need_commented.html.haml new file mode 100644 index 0000000..6d703b2 --- /dev/null +++ b/app/views/customer_mailer/need_commented.html.haml @@ -0,0 +1,10 @@ +%p Bonjour, + +%p + Un autre utilisateur a laissé un commentaire sur le besoin + %strong= @need.title + +%p + %strong= @comment.customer.fullname + +%p= @comment.content diff --git a/app/views/customer_mailer/need_negociated.html.haml b/app/views/customer_mailer/need_negociated.html.haml new file mode 100644 index 0000000..c133d38 --- /dev/null +++ b/app/views/customer_mailer/need_negociated.html.haml @@ -0,0 +1,10 @@ +%p Bonjour, + +%p + Le besoin + %strong= @need.title + vient d'être négocié !" + +%p Rendez-vous sur notre site afin de voir notre proposition + +%p Merci diff --git a/app/views/customer_mailer/need_negociation_failed.html.haml b/app/views/customer_mailer/need_negociation_failed.html.haml new file mode 100644 index 0000000..45188de --- /dev/null +++ b/app/views/customer_mailer/need_negociation_failed.html.haml @@ -0,0 +1,8 @@ +%p Bonjour, + +%p + Nous avons le regret de vous annoncer que le besoin + %strong= @need.title + n'a pas pu être négocié. + +%p Merci diff --git a/app/views/customer_mailer/offer_accepted.html.haml b/app/views/customer_mailer/offer_accepted.html.haml new file mode 100644 index 0000000..d4db561 --- /dev/null +++ b/app/views/customer_mailer/offer_accepted.html.haml @@ -0,0 +1,7 @@ +%p Bonjour, + +%p + Vous venez d'accepter une proposition pour le besoin + %strong= @accepted_offer.offer.need.title + +%p Merci diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml index f40a606..426e90b 100755 --- a/app/views/layouts/public.html.haml +++ b/app/views/layouts/public.html.haml @@ -3,59 +3,59 @@ %html{:lang => "fr", "xml:lang" => "fr", :xmlns => "http://www.w3.org/1999/xhtml"} %head %title Négos - - - + + + %meta{:name=>"viewport", :content=>"width=device-width,initial-scale=1"} %meta{ :"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8" } %meta{ :"name" => "Description", :content => @description } - %meta{ :"name" => "Keywords", :content => @keywords } + %meta{ :"name" => "Keywords", :content => @keywords } =# - + = javascript_include_tag "public" - - - = csrf_meta_tag + + + = csrf_meta_tag =#render :partial => "public/shared/ga" - - = stylesheet_link_tag 'public' - = stylesheet_link_tag '/fonts/Stylograph/stylesheet.css' + + = stylesheet_link_tag 'public' + = stylesheet_link_tag '/fonts/Stylograph/stylesheet.css' - + =javascript_include_tag "https://maps.googleapis.com/maps/api/js?libraries=places&sensor=false" - - - + + + %body - - - + + + .top - - + + #menu - - + + =render :partial => "public/shared/menu" .clear - =link_to image_tag("/logo.png", :id => "logo"), "/" + + -if @biglogo + =link_to image_tag("/logo.png", :id => "big-logo"), "/" + -else + =link_to image_tag("/logo.png", :id => "logo"), "/" #main =yield - + %br %br %br .clear =#render :partial => "public/shared/bottom" - + #flashs= bootstrap_flash - - - - diff --git a/app/views/public/customers_auths/new.haml b/app/views/public/customers_auths/new.haml index d489cba..0ef351f 100755 --- a/app/views/public/customers_auths/new.haml +++ b/app/views/public/customers_auths/new.haml @@ -1,10 +1,10 @@ -.row +.row.container .col-md-6 .connexion_form - %h1 Vous avez déjà un compte ? + %h1 Déjà membre ? = form_tag public_customers_auths_path do =hidden_field_tag :for_annonce, params[:for_annonce] diff --git a/app/views/public/needs/_form.html.haml b/app/views/public/needs/_form.html.haml index 84aab73..48b6b5e 100755 --- a/app/views/public/needs/_form.html.haml +++ b/app/views/public/needs/_form.html.haml @@ -1,6 +1,9 @@ = semantic_form_for [:public, @need] do |f| =f.inputs do = f.input :title, :label => "Titre de votre besoin" + = f.input :devis, type: :file, :label => "Devis/Offre (Fichier au format PDF)" + -if @need.devis? + = link_to ic(:download) + " Télécharger le devis actuel", public_need_download_devis_path(@need), class: "btn btn-primary" = f.input :category, :as => :select, include_blank: "Toute catégorie", :collection => @tree.map{|c| [(c.level > 0 ? ('   ' * (c.level - 1)) + "|- ": "").html_safe + c.name, c.id]}, label: "Catégorie de besoin" = f.input :description, :label => "Description", :rows => 5, :input_html => {:style => "height:100px;"} %br diff --git a/app/views/public/needs/_need_item.html.haml b/app/views/public/needs/_need_item.html.haml index 45111cb..d144adc 100755 --- a/app/views/public/needs/_need_item.html.haml +++ b/app/views/public/needs/_need_item.html.haml @@ -1,9 +1,14 @@ -.col-md-6 +.col-md-12 .padding.need-item %h4 =link_to need.title.upcase, public_need_path(need) + -if need.image_file + %div.need-image{style: "background-image: url('#{need.image_file.file.url}')"} + -else + %div.need-image + -# -if need.author -# %p.info=i(:"clock-o") + " Ajouté il y a #{time_ago_in_words(need.created_at)} par #{need.author.anonyme_nick}" -# -else @@ -39,7 +44,7 @@ - %p.description=truncate(need.description, length: 100) + %p.description=need.description .counters .item=i(:"hand-paper-o") + " " + need.wishes.length.to_s @@ -54,13 +59,13 @@ -if(need.customers.include?(current_customer)) =link_to "Négociation en cours...", public_need_path(need), class: "btn btn-warning pull-right" -else - =link_to i(:"times-circle") + " Trop tard pour vous !", public_need_path(need) , class: "btn btn-danger pull-right" + =link_to i(:"times-circle") + " Négociation en cours...", public_need_path(need) , class: "btn btn-warning pull-right" -elsif(need.negociated?) -if(need.customers.include?(current_customer)) =link_to i(:"download") +" Voir les propositions", public_need_path(need), class: "btn btn-success pull-right" -else - =link_to i(:"times-circle") + " Trop tard pour vous !", public_need_path(need) , class: "btn btn-danger pull-right" + =link_to i(:"times-circle") + " Négociation terminée", public_need_path(need) , class: "btn btn-success pull-right" diff --git a/app/views/public/needs/show.html.haml b/app/views/public/needs/show.html.haml index 86977f7..1f06fbc 100755 --- a/app/views/public/needs/show.html.haml +++ b/app/views/public/needs/show.html.haml @@ -39,30 +39,34 @@ %p.description= @need.description + -if @need.image_file + %img{src: @need.image_file.file.url} + %br + %br + -if @need.verified? -if @need.customers.include?(current_customer) .alert.alert-success %h3= i(:"check") + ' Vous êtes intéressé par ce besoin' - %p Marquer votre interêt pour un besoin vous permettra d'accéder à des propositions intéressantes si nous décidons par la suite de négocier ce besoin auprès de nos fournisseurs. + %p Marquer votre intérêt pour un besoin vous permettra d’accéder à des offres intéressantes, si nous décidons par la suite de le négocier auprès des fournisseurs, -else .alert.alert-info %h3 Vous avez aussi ce besoin ? signalez-le nous ! %p Vous pouvez marquer votre interêt pour ce besoin en cliquant sur le bouton Ça m'intéresse ! - %p Si il y a un nombre suffisant de personnes avec ce même besoin, une négociation sera entamée auprès de nos fournisseurs afin de vous faire une proposition au meilleur prix. - %p Vous ensuite libre d'accepter ou non la proposition + %p Si il y a un nombre suffisant de personnes intéressées par ce même besoin, une négociation sera entamée auprès des fournisseurs afin de vous faire une offre intéressante. + %p Une fois la négociation terminée, vous serez libre d'accepter ou non la proposition. -elsif @need.negociating? -if @need.customers.include?(current_customer) .alert.alert-warning %h3 Négociation en cours... - %p Ce besoin a suscité un interêt suffisant pour que nous engagions une négociation afin de vous proposer cet article au meilleur prix. - %p Vous avez marqué votre interêt pour ce besoin et vous serez donc prevenu dès que la négociation sera terminée. - %p Une ou plusieurs propositions vous seront faites et vous serez libre de les accepter ou non. - %p Attention, accepter la proposition vous engage à payer. + %p Ce besoin a suscité un interêt suffisant pour que nous engagions une négociation auprès des fournisseurs. + %p Une fois la négociation terminée, vous serez libre d’accepter ou non l’offre proposée. + %p Afin d’en bénéficier, merci de nous retourner au plus vite le mandat signé -else .alert.alert-warning %h3 Négociation en cours... - %p Ce besoin a suscité un interêt suffisant pour que nous engagions une négociation afin de vous proposer cet article au meilleur prix. + %p Ce besoin a suscité un interêt suffisant pour que nous engagions une négociation auprès des fournisseurs. .alert.alert-danger %p Malheureusement vous n'avez pas marqué votre interêt pour ce besoin pendant la période de sondage, vous ne pourrez donc pas profiter de cette négociation. -elsif @need.negociated? @@ -71,7 +75,7 @@ %h3 Négociation terminée %p= "Nous avons négocié ce besoin à partir de #{number_to_currency(offers.first.price, locale: :fr)}" %p Vous avez maintenant le choix d'accepter ou refuser la proposition. - %p Attention, accepter la proposition vous engage à payer. + %p Une fois la proposition acceptée, vous devrez nous retourner au plus vite le mandat signé -else .alert.alert-success %h3 Négociation terminée @@ -111,14 +115,15 @@ =link_to i(:"check") + " Accepter la proposition", accept_public_need_offer_path(@need, offer), data: {confirm: "Voulez-vous vraiment accepter cette proposition ? Attention, cette action vous engage à payer la somme proposée."}, class: "btn btn-lg btn-success " -else .offer-accepted - =i(:"check") + " Propositions Acceptée" + =i(:"check") + " Proposition Acceptée" .my-account-link - Consulter vos propositions acceptées depuis la rubrique + Vous devez maintenant nous retourner le mandat signé, rendez-vous rubrique =link_to "Mon compte", public_my_account_path + pour gérer vos propositions acceptées. -else .offer-not-aceptable - Vous n'êtes pas intéressé + Proposition non disponible .clear diff --git a/config/routes.rb b/config/routes.rb index 90fafb6..d775371 100755 --- a/config/routes.rb +++ b/config/routes.rb @@ -103,6 +103,7 @@ Rails.application.routes.draw do end resources :needs do + get :download_devis resources :messages resources :offers do member do @@ -265,6 +266,7 @@ Rails.application.routes.draw do resources :need_categories resources :needs do + get :download_devis resources :messages resources :wishes resources :offers do diff --git a/db/migrate/20160317130441_add_image_and_file_to_need.rb b/db/migrate/20160317130441_add_image_and_file_to_need.rb new file mode 100644 index 0000000..bd40cbd --- /dev/null +++ b/db/migrate/20160317130441_add_image_and_file_to_need.rb @@ -0,0 +1,6 @@ +class AddImageAndFileToNeed < ActiveRecord::Migration + def change + add_column :needs, :devis, :string + add_reference :needs, :image_file, index: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 1107aa4..47998cc 100755 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160308112733) do +ActiveRecord::Schema.define(version: 20160317130441) do create_table "accepted_offers", force: :cascade do |t| t.datetime "created_at", null: false @@ -438,19 +438,22 @@ ActiveRecord::Schema.define(version: 20160308112733) do add_index "need_categories", ["parent_id"], name: "index_need_categories_on_parent_id", using: :btree create_table "needs", force: :cascade do |t| - t.string "title", limit: 255 - t.text "description", limit: 65535 - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "author_id", limit: 4 + t.string "title", limit: 255 + t.text "description", limit: 65535 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "author_id", limit: 4 t.datetime "deleted_at" - t.string "state", limit: 255 - t.integer "category_id", limit: 4 + t.string "state", limit: 255 + t.integer "category_id", limit: 4 + t.string "devis", limit: 255 + t.integer "image_file_id", limit: 4 end add_index "needs", ["author_id"], name: "index_needs_on_author_id", using: :btree add_index "needs", ["category_id"], name: "index_needs_on_category_id", using: :btree add_index "needs", ["deleted_at"], name: "index_needs_on_deleted_at", using: :btree + add_index "needs", ["image_file_id"], name: "index_needs_on_image_file_id", using: :btree add_index "needs", ["title"], name: "index_needs_on_title", using: :btree create_table "newsgroups", force: :cascade do |t| diff --git a/public/placeholder.png b/public/placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..541d531c5d0a44d47534d30dd7ef161b6824af69 GIT binary patch literal 6909 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 QhW0oCFf+rV^UmS_1?=|+xBvhE literal 0 HcmV?d00001