Files
2026-04-24 22:01:18 +00:00

334 lines
11 KiB
Ruby

# This file is a part of Redmine CRM (redmine_contacts) plugin,
# customer relationship management plugin for Redmine
#
# Copyright (C) 2010-2018 RedmineUP
# http://www.redmineup.com/
#
# redmine_contacts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# redmine_contacts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
class DealsController < ApplicationController
unloadable
PRICE_TYPE_PULLDOWN = [l(:label_price_fixed_bid), l(:label_price_per_hour)]
before_action :find_deal, :only => [:show, :edit, :update, :destroy]
before_action :find_project, :only => [:new, :create, :update_form]
before_action :bulk_find_deals, :only => [:bulk_update, :bulk_edit, :bulk_destroy, :context_menu]
before_action :authorize, :except => [:index]
before_action :find_optional_project, :only => [:index]
before_action :update_deal_from_params, :only => [:edit, :update]
before_action :build_new_deal_from_params, :only => [:new, :update_form]
before_action :find_deal_attachments, :only => :show
skip_before_filter :authorize, :only => :add_product_line if RedmineContacts.products_plugin_installed?
accept_api_auth :index, :show, :create, :update, :destroy
helper :attachments
helper :timelog
helper :watchers
helper :custom_fields
helper :context_menus
helper :sort
helper :crm_queries
helper :notes
helper :queries
helper :calendars
include QueriesHelper
include CrmQueriesHelper
include WatchersHelper
include DealsHelper
include SortHelper
if RedmineContacts.products_plugin_installed?
include ProductsHelper
helper :products
end
def index
retrieve_crm_query('deal')
sort_init(@query.sort_criteria.empty? ? [['created_on', 'desc']] : @query.sort_criteria)
sort_update(@query.sortable_columns)
@query.sort_criteria = sort_criteria.to_a
if @query.valid?
case params[:format]
when 'csv', 'pdf'
@limit = Setting.issues_export_limit.to_i
when 'atom'
@limit = Setting.feeds_limit.to_i
when 'xml', 'json'
@offset, @limit = api_offset_and_limit
else
@limit = per_page_option
end
@deals_count = @query.object_count
@deals_scope = @query.objects_scope
@deal_amount = @query.deal_amount
@deal_weighted_amount = @query.weighted_amount
@deals_pages = Paginator.new @deals_count, @limit, params['page']
@offset ||= @deals_pages.offset
@deal_count_by_group = @query.object_count_by_group
@deals = @query.results_scope(
:include => [{ :contact => [:avatar, :projects, :address] }, :author],
:search => params[:search],
:order => sort_clause,
:limit => @limit,
:offset => @offset
)
if deals_list_style == 'crm_calendars/crm_calendar'
retrieve_crm_calendar(:start_date_field => 'due_date')
@calendar.events = @query.results_scope(
:include => [:contact],
:search => params[:search],
:conditions => ['due_date BETWEEN ? AND ?', @calendar.startdt, @calendar.enddt]
)
end
respond_to do |format|
format.html { request.xhr? ? render(:partial => deals_list_style, :layout => false) : last_notes }
format.api
format.atom { render_feed(@deals, :title => "#{@project || Setting.app_title}: #{l(:label_order_plural)}") }
format.csv { send_data(deals_to_csv(@deals), :type => 'text/csv; header=present', :filename => 'deals.csv') }
format.pdf { send_data(deals_to_pdf(@deals, @project, @query), :type => 'application/pdf', :filename => 'deals.pdf') }
end
else
respond_to do |format|
format.html { render(:template => 'deals/index', :layout => !request.xhr?) }
format.any(:atom, :csv, :pdf) { render(:nothing => true) }
format.api { render_validation_errors(@query) }
end
end
rescue ActiveRecord::RecordNotFound
render_404
end
def show
@note = DealNote.new(:created_on => Time.now)
respond_to do |format|
format.html do
@deal_issues = @deal.issues.visible
@deal.viewed
@deal_events = (@deal.deal_processes.where("#{DealProcess.table_name}.old_value IS NOT NULL").includes([:to, :from, :author]) | @deal.notes.includes([:attachments, :author])).map{|o| {:date => o.is_a?(DealProcess) ? o.created_at : o.created_on, :author => o.author, :object => o} }
@deal_events.sort! { |x, y| y[:date] <=> x[:date] }
end
format.api
end
end
def new
end
def create
@deal = Deal.new
@deal.safe_attributes = params[:deal]
@deal.project = @project
@deal.author ||= User.current
@deal.price = parsed_price(params[:deal][:price])
@deal.init_deal_process(User.current)
if @deal.save
flash[:notice] = l(:notice_successful_create)
respond_to do |format|
format.html { redirect_to(params[:continue] ? { :action => 'new' } : { :action => 'show', :id => @deal }) }
format.api { render :action => 'show', :status => :created, :location => deal_url(@deal) }
end
else
respond_to do |format|
format.html { render :action => 'new' }
format.api { render_validation_errors(@deal) }
end
end
end
def update
@deal.init_deal_process(User.current)
@deal.safe_attributes = params[:deal]
if @deal.save
# @deal.contacts = [Contact.find(params[:contacts])] if params[:contacts]
retrieve_crm_query('deal')
@deals_scope = @query.objects_scope
flash[:notice] = l(:notice_successful_update)
respond_to do |format|
format.html { redirect_back_or_default(:action => 'show', :id => @deal) }
format.api { render_api_ok }
format.js { render :update_total }
end
else
respond_to do |format|
format.html { render :action => 'edit' }
format.api { render_validation_errors(@deal) }
format.js { render "alert('Error!')" }
end
end
end
def edit
respond_to do |format|
format.html {}
format.xml {}
end
end
def destroy
if @deal.destroy
flash[:notice] = l(:notice_successful_delete)
respond_to do |format|
format.html { redirect_to :action => 'index', :project_id => params[:project_id] }
format.api { render_api_ok }
end
else
flash[:error] = l(:notice_unsuccessful_save)
end
end
def context_menu
@deal = @deals.first if @deals.size == 1
@can = { :edit => User.current.allowed_to?(:edit_deals, @projects),
:delete => User.current.allowed_to?(:delete_deals, @projects) }
@back = back_url
render :layout => false
end
def bulk_destroy
@deals.each do |deal|
begin
deal.reload.destroy
rescue ::ActiveRecord::RecordNotFound # raised by #reload if deal no longer exists
# nothing to do, deal was already deleted (eg. by a parent)
end
end
respond_to do |format|
format.html { redirect_back_or_default(:action => 'index', :project_id => params[:project_id]) }
format.api { head :ok }
end
end
def bulk_edit
@available_statuses = @projects.map(&:deal_statuses).inject { |memo, w| memo & w }
@custom_fields = DealCustomField.order(:name)
@available_categories = @projects.map(&:deal_categories).inject { |memo, w| memo & w }
@assignables = @projects.map(&:assignable_users).inject { |memo, a| memo & a }
end
def bulk_update
unsaved_deal_ids = []
@deals.each do |deal|
deal.reload
deal.init_deal_process(User.current)
deal.safe_attributes = parse_params_for_bulk_deal_attributes(params)
unless deal.save
# Keep unsaved deal ids to display them in flash error
unsaved_deal_ids << deal.id
end
if params[:note] && !params[:note][:content].blank?
note = DealNote.new
note.safe_attributes = params[:note]
note.author = User.current
deal.notes << note
end
end
set_flash_from_bulk_contact_save(@deals, unsaved_deal_ids)
redirect_back_or_default(:controller => 'deals', :action => 'index', :project_id => @project)
end
private
def last_notes(count = 5)
# TODO: Исправить говнокод этот и выделить все в плагин acts-as-noteble
scope = DealNote.where({})
scope = scope.where("#{Deal.table_name}.project_id = ?", @project.id) if @project
@last_notes = scope.visible.order("#{DealNote.table_name}.created_on DESC").limit(count)
end
def build_new_deal_from_params
if params[:id].blank?
@deal = Deal.new
@deal.assigned_to_id = User.current.id
@deal.name = params[:name] if params[:name]
@deal.contact = Contact.find(params[:contact_id]) if params[:contact_id]
if params[:copy_from]
begin
@copy_from = Deal.visible.find(params[:copy_from])
@deal.copy_from(@copy_from)
rescue ActiveRecord::RecordNotFound
render_404
return
end
end
else
@deal = Deal.visible.find(params[:id])
end
@deal.project = @project
@deal.author ||= User.current
@deal.safe_attributes = params[:deal]
@available_watchers = (@deal.project.users.sort + @deal.watcher_users).uniq
end
def update_deal_from_params
end
def update_form
end
def find_deal_attachments
@deal_attachments = Attachment.where(:container_type => 'Note', :container_id => @deal.notes.map(&:id)).order(:created_on)
end
def bulk_find_deals
@deals = Deal.where(:id => (params[:id] || params[:ids])).includes([:project, :contact])
raise ActiveRecord::RecordNotFound if @deals.empty?
if @deals.detect { |deal| !deal.visible? }
deny_access
return
end
@projects = @deals.collect(&:project).compact.uniq
@project = @projects.first if @projects.size == 1
rescue ActiveRecord::RecordNotFound
render_404
end
def find_deal
@deal = Deal.where(:id => params[:id]).includes([:project, :status, :category]).first
@project = @deal.project
rescue ActiveRecord::RecordNotFound
render_404
end
def find_project(project_id = nil)
project_id ||= (params[:deal] && params[:deal][:project_id]) || params[:project_id]
@project = Project.find(project_id)
rescue ActiveRecord::RecordNotFound
render_404
end
def parse_params_for_bulk_deal_attributes(params)
attributes = (params[:deal] || {}).reject { |_k, v| v.blank? }
attributes.keys.each { |k| attributes[k] = '' if attributes[k] == 'none' }
attributes[:custom_field_values].reject! { |_k, v| v.blank? } if attributes[:custom_field_values]
attributes
end
def parsed_price(price)
return unless price
price.gsub!(ContactsSetting.thousands_delimiter, '')
price.gsub!(ContactsSetting.decimal_separator, '.')
price.to_f
end
end