Modelos hechos
git-svn-id: https://192.168.0.254/svn/Rodax.redmine_rodax_crm/trunk@3 ff88604e-da85-c949-a72f-fc3aa3ba3724
This commit is contained in:
parent
946162f5d0
commit
2b75d1e4cf
2
app/helpers/contract_categories_helper.rb
Normal file
2
app/helpers/contract_categories_helper.rb
Normal file
@ -0,0 +1,2 @@
|
||||
module ContractCategoriesHelper
|
||||
end
|
||||
120
app/models/contract.rb
Normal file
120
app/models/contract.rb
Normal file
@ -0,0 +1,120 @@
|
||||
class Contract < ActiveRecord::Base
|
||||
unloadable
|
||||
|
||||
belongs_to :project
|
||||
belongs_to :author, :class_name => "User", :foreign_key => "author_id"
|
||||
belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
|
||||
belongs_to :category, :class_name => 'ContractCategory', :foreign_key => 'category_id'
|
||||
belongs_to :contact
|
||||
belongs_to :status, :class_name => "ContractStatus", :foreign_key => "status_id"
|
||||
has_many :contracts, :class_name => "contract", :foreign_key => "reference_id"
|
||||
has_many :notes, :as => :source, :class_name => 'ContractNote', :dependent => :delete_all, :order => "created_on DESC"
|
||||
has_many :contract_processes, :dependent => :delete_all
|
||||
has_and_belongs_to_many :related_contacts, :class_name => 'Contact', :order => "#{Contact.table_name}.last_name, #{Contact.table_name}.first_name", :uniq => true
|
||||
|
||||
|
||||
named_scope :visible, lambda {|*args| { :include => :project,
|
||||
:conditions => Project.allowed_to_condition(args.first || User.current, :view_contracts)} }
|
||||
|
||||
named_scope :deletable, lambda {|*args| { :include => :project,
|
||||
:conditions => Project.allowed_to_condition(args.first || User.current, :delete_contracts) }}
|
||||
|
||||
named_scope :live_search, lambda {|search| {:conditions => ["(#{Contract.table_name}.name LIKE ?)", "%#{search}%"] }}
|
||||
|
||||
named_scope :open, :include => :status, :conditions => ["#{ContractStatus.table_name}.is_closed = ?", false]
|
||||
|
||||
acts_as_customizable
|
||||
acts_as_viewable
|
||||
acts_as_watchable
|
||||
acts_as_attachable :view_permission => :view_contracts,
|
||||
:delete_permission => :edit_contracts
|
||||
|
||||
acts_as_event :datetime => :created_on,
|
||||
:url => Proc.new {|o| {:controller => 'contracts', :action => 'show', :id => o}},
|
||||
:type => 'icon-report',
|
||||
:title => Proc.new {|o| o.name },
|
||||
:description => Proc.new {|o| [o.price, o.contact ? o.contact.name : nil, o.background].join(' ').strip }
|
||||
|
||||
acts_as_searchable :columns => ["#{table_name}.name",
|
||||
"#{table_name}.background"],
|
||||
:include => [:project],
|
||||
# sort by id so that limited eager loading doesn't break with postgresql
|
||||
:order_column => "#{table_name}.id"
|
||||
|
||||
|
||||
|
||||
validates_presence_of :name
|
||||
validates_numericality_of :price, :allow_nil => true
|
||||
|
||||
after_save :create_contract_process
|
||||
|
||||
|
||||
include ActionView::Helpers::NumberHelper
|
||||
include ::ContractsHelper
|
||||
|
||||
def after_initialize
|
||||
if new_record?
|
||||
# set default values for new records only
|
||||
self.status ||= ContractStatus.default
|
||||
end
|
||||
end
|
||||
|
||||
def avatar
|
||||
|
||||
end
|
||||
|
||||
def full_name
|
||||
result = ''
|
||||
result << self.contact.name + ": " unless self.contact.blank?
|
||||
result << self.name
|
||||
end
|
||||
|
||||
def all_contacts
|
||||
@all_contacts ||= ([self.contact] + self.related_contacts ).uniq
|
||||
end
|
||||
|
||||
def self.available_users(prj=nil)
|
||||
cond = "(1=1)"
|
||||
cond << " AND #{Contract.table_name}.project_id = #{prj.id}" if prj
|
||||
User.active.find(:all, :select => "DISTINCT #{User.table_name}.*", :joins => "JOIN #{Contract.table_name} ON #{Contract.table_name}.assigned_to_id = #{User.table_name}.id", :conditions => cond, :order => "#{User.table_name}.lastname, #{User.table_name}.firstname")
|
||||
end
|
||||
|
||||
|
||||
def init_contract_process(author)
|
||||
@current_contract_process ||= ContractProcess.new(:contract => self, :author => (author || User.current))
|
||||
@contract_status_before_change = self.new_record? ? nil : self.status_id
|
||||
updated_on_will_change!
|
||||
@current_contract_process
|
||||
end
|
||||
|
||||
def create_contract_process
|
||||
if @current_contract_process && !(@contract_status_before_change == self.status_id)
|
||||
@current_contract_process.old_value = @contract_status_before_change
|
||||
@current_contract_process.value = self.status_id
|
||||
@current_contract_process.save
|
||||
# reset current journal
|
||||
init_contract_process @current_contract_process.author
|
||||
end
|
||||
end
|
||||
|
||||
def visible?(usr=nil)
|
||||
(usr || User.current).allowed_to?(:view_contracts, self.project)
|
||||
end
|
||||
|
||||
def editable?(usr=nil)
|
||||
(usr || User.current).allowed_to?(:edit_contracts, self.project)
|
||||
end
|
||||
|
||||
def destroyable?(usr=nil)
|
||||
(usr || User.current).allowed_to?(:delete_contracts, self.project)
|
||||
end
|
||||
|
||||
|
||||
def info
|
||||
result = ""
|
||||
result = self.status.name if self.status
|
||||
result = result + " - " + contract_price(self) if !self.price.blank?
|
||||
result
|
||||
end
|
||||
|
||||
end
|
||||
26
app/models/contract_category.rb
Normal file
26
app/models/contract_category.rb
Normal file
@ -0,0 +1,26 @@
|
||||
class ContractCategory < ActiveRecord::Base
|
||||
unloadable
|
||||
belongs_to :project
|
||||
has_many :contracts, :foreign_key => 'category_id', :dependent => :nullify
|
||||
|
||||
validates_presence_of :name
|
||||
validates_uniqueness_of :name, :scope => [:project_id]
|
||||
validates_length_of :name, :maximum => 30
|
||||
|
||||
alias :destroy_without_reassign :destroy
|
||||
|
||||
# Destroy the category
|
||||
# If a category is specified, issues are reassigned to this category
|
||||
def destroy(reassign_to = nil)
|
||||
if reassign_to && reassign_to.is_a?(ContractCategory) && reassign_to.project == self.project
|
||||
Contract.update_all("category_id = #{reassign_to.id}", "category_id = #{id}")
|
||||
end
|
||||
destroy_without_reassign
|
||||
end
|
||||
|
||||
def <=>(category)
|
||||
name <=> category.name
|
||||
end
|
||||
|
||||
def to_s; name end
|
||||
end
|
||||
7
app/models/contract_custom_field.rb
Normal file
7
app/models/contract_custom_field.rb
Normal file
@ -0,0 +1,7 @@
|
||||
class ContractCustomField < ActiveRecord::Base
|
||||
unloadable
|
||||
|
||||
def type_name
|
||||
:label_contract_plural
|
||||
end
|
||||
end
|
||||
23
app/models/contract_note.rb
Normal file
23
app/models/contract_note.rb
Normal file
@ -0,0 +1,23 @@
|
||||
class ContractNote < Note
|
||||
unloadable
|
||||
belongs_to :contract, :foreign_key => :source_id
|
||||
|
||||
acts_as_searchable :columns => ["#{table_name}.content"],
|
||||
:include => [:contract => :project],
|
||||
:project_key => "#{Project.table_name}.id",
|
||||
:permission => :view_contracts,
|
||||
# sort by id so that limited eager loading doesn't break with postgresql
|
||||
:order_column => "#{table_name}.id"
|
||||
|
||||
acts_as_activity_provider :type => 'contacts',
|
||||
:permission => :view_contracts,
|
||||
:author_key => :author_id,
|
||||
:find_options => {:include => [:contract => :project],
|
||||
:conditions => {:source_type => 'Contract'}}
|
||||
|
||||
named_scope :visible, lambda {|*args| { :include => [:contract => :project],
|
||||
:conditions => Project.allowed_to_condition(args.first || User.current, :view_contracts) +
|
||||
" AND (#{ContractNote.table_name}.source_type = 'Contract')"} }
|
||||
|
||||
|
||||
end
|
||||
7
app/models/contract_process.rb
Normal file
7
app/models/contract_process.rb
Normal file
@ -0,0 +1,7 @@
|
||||
class ContractProcess < ActiveRecord::Base
|
||||
unloadable
|
||||
|
||||
belongs_to :author, :class_name => "User", :foreign_key => "author_id"
|
||||
belongs_to :contract
|
||||
|
||||
end
|
||||
78
app/models/contract_status.rb
Normal file
78
app/models/contract_status.rb
Normal file
@ -0,0 +1,78 @@
|
||||
class ContractStatus < ActiveRecord::Base
|
||||
unloadable
|
||||
has_and_belongs_to_many :projects
|
||||
has_many :contracts, :foreign_key => 'status_id', :dependent => :nullify
|
||||
|
||||
acts_as_list
|
||||
|
||||
validates_presence_of :name
|
||||
validates_uniqueness_of :name
|
||||
validates_length_of :name, :maximum => 30
|
||||
validates_format_of :name, :with => /^[\w\s\'\-]*$/i
|
||||
|
||||
def after_save
|
||||
ContractStatus.update_all("is_default=#{connection.quoted_false}", ['id <> ?', id]) if self.is_default?
|
||||
end
|
||||
|
||||
# Returns the default status for new Contracts
|
||||
def self.default
|
||||
find(:first, :conditions =>["is_default=?", true])
|
||||
end
|
||||
|
||||
# Returns an array of all statuses the given role can switch to
|
||||
# Uses association cache when called more than one time
|
||||
def new_statuses_allowed_to(roles, tracker)
|
||||
if roles && tracker
|
||||
role_ids = roles.collect(&:id)
|
||||
new_statuses = workflows.select {|w| role_ids.include?(w.role_id) && w.tracker_id == tracker.id}.collect{|w| w.new_status}.compact.sort
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
# Same thing as above but uses a database query
|
||||
# More efficient than the previous method if called just once
|
||||
def find_new_statuses_allowed_to(roles, tracker)
|
||||
if roles && tracker
|
||||
workflows.find(:all,
|
||||
:include => :new_status,
|
||||
:conditions => { :role_id => roles.collect(&:id),
|
||||
:tracker_id => tracker.id}).collect{ |w| w.new_status }.compact.sort
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def new_status_allowed_to?(status, roles, tracker)
|
||||
if status && roles && tracker
|
||||
!workflows.find(:first, :conditions => {:new_status_id => status.id, :role_id => roles.collect(&:id), :tracker_id => tracker.id}).nil?
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def color_name
|
||||
return "#" + "%06x" % self.color unless self.color.nil?
|
||||
end
|
||||
|
||||
def color_name=(clr)
|
||||
self.color = clr.from(1).hex
|
||||
end
|
||||
|
||||
|
||||
def <=>(status)
|
||||
position <=> status.position
|
||||
end
|
||||
|
||||
def to_s; name end
|
||||
|
||||
private
|
||||
def check_integrity
|
||||
raise "Can't delete status" if Contract.find(:first, :conditions => ["status_id=?", self.id])
|
||||
end
|
||||
|
||||
# Deletes associated workflows
|
||||
def delete_workflows
|
||||
Workflow.delete_all(["old_status_id = :id OR new_status_id = :id", {:id => id}])
|
||||
end
|
||||
end
|
||||
@ -162,4 +162,7 @@ es:
|
||||
field_age: Age
|
||||
label_vcf_import: Import from vCard
|
||||
label_mail_from: From
|
||||
permission_import_contacts: Import contacts
|
||||
permission_import_contacts: Import contacts
|
||||
|
||||
#2.2.2-rodax
|
||||
label_contract_plural: Categorías de contratos
|
||||
31
db/migrate/026_create_contracts.rb
Normal file
31
db/migrate/026_create_contracts.rb
Normal file
@ -0,0 +1,31 @@
|
||||
class CreateContracts < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :contracts do |t|
|
||||
t.string :name
|
||||
t.text :background
|
||||
t.integer :currency
|
||||
t.integer :duration
|
||||
t.decimal :price
|
||||
t.integer :price_type
|
||||
t.integer :project_id
|
||||
t.integer :author_id
|
||||
t.integer :assigned_to_id
|
||||
t.integer :status_id, :default => 0, :null => false
|
||||
t.integer :contact_id
|
||||
t.integer :category_id
|
||||
t.datetime :created_on
|
||||
t.datetime :updated_on
|
||||
t.datetime :start_date
|
||||
t.datetime :end_date
|
||||
end
|
||||
add_index :contracts, :contact_id
|
||||
add_index :contracts, :status_id
|
||||
add_index :contracts, :author_id
|
||||
add_index :contracts, :category_id
|
||||
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :contracts
|
||||
end
|
||||
end
|
||||
2
db/migrate/027_create_contract_notes.rb
Normal file
2
db/migrate/027_create_contract_notes.rb
Normal file
@ -0,0 +1,2 @@
|
||||
class CreateContractNotes < ActiveRecord::Migration
|
||||
end
|
||||
13
db/migrate/028_create_contract_categories.rb
Normal file
13
db/migrate/028_create_contract_categories.rb
Normal file
@ -0,0 +1,13 @@
|
||||
class CreateContractCategories < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :contract_categories do |t|
|
||||
t.string :name, :null => false
|
||||
t.integer :project_id
|
||||
end
|
||||
add_index :contract_categories, :project_id
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :contract_categories
|
||||
end
|
||||
end
|
||||
2
db/migrate/029_create_contract_custom_fields.rb
Normal file
2
db/migrate/029_create_contract_custom_fields.rb
Normal file
@ -0,0 +1,2 @@
|
||||
class CreateContractCustomFields < ActiveRecord::Migration
|
||||
end
|
||||
19
db/migrate/031_create_contract_statuses.rb
Normal file
19
db/migrate/031_create_contract_statuses.rb
Normal file
@ -0,0 +1,19 @@
|
||||
class CreateContractStatuses < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :contract_statuses do |t|
|
||||
t.string :name, :null => false
|
||||
t.integer :position
|
||||
t.boolean :is_default, :default => false, :null => false
|
||||
t.boolean :is_closed, :default => false, :null => false
|
||||
t.integer :color, :default => 11184810, :null => false
|
||||
end
|
||||
add_index :contract_statuses, [:is_closed]
|
||||
ContractStatus.create(:name => "Pending", :is_closed => false, :is_default => true, :color => "AAAAAA".hex)
|
||||
ContractStatus.create(:name => "Won", :is_closed => true, :is_default => false, :color => "008000".hex)
|
||||
ContractStatus.create(:name => "Lost", :is_closed =>true, :is_default => false, :color => "FF0000".hex)
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :contract_statuses
|
||||
end
|
||||
end
|
||||
17
db/migrate/032_create_contract_processes.rb
Normal file
17
db/migrate/032_create_contract_processes.rb
Normal file
@ -0,0 +1,17 @@
|
||||
class CreateContractProcesses < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :contract_processes do |t|
|
||||
t.integer :contract_id, :null => false
|
||||
t.integer :author_id, :null => false
|
||||
t.integer :old_value
|
||||
t.integer :value, :null => false
|
||||
t.datetime :created_at
|
||||
end
|
||||
add_index :contract_processes, [:author_id]
|
||||
add_index :contract_processes, [:contract_id]
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :contract_processes
|
||||
end
|
||||
end
|
||||
13
db/migrate/033_create_contract_statuses_projects.rb
Normal file
13
db/migrate/033_create_contract_statuses_projects.rb
Normal file
@ -0,0 +1,13 @@
|
||||
class CreateContractStatusesProjects < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :contract_statuses_projects, :id => false do |t|
|
||||
t.integer :project_id, :default => 0, :null => false
|
||||
t.integer :contract_status_id, :default => 0, :null => false
|
||||
end
|
||||
add_index :contract_statuses_projects, [:project_id, :contract_status_id]
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :contract_statuses_projects
|
||||
end
|
||||
end
|
||||
5
test/fixtures/contract_categories.yml
vendored
Normal file
5
test/fixtures/contract_categories.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
one:
|
||||
id: 1
|
||||
two:
|
||||
id: 2
|
||||
5
test/fixtures/contract_custom_fields.yml
vendored
Normal file
5
test/fixtures/contract_custom_fields.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
one:
|
||||
id: 1
|
||||
two:
|
||||
id: 2
|
||||
5
test/fixtures/contract_notes.yml
vendored
Normal file
5
test/fixtures/contract_notes.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
one:
|
||||
id: 1
|
||||
two:
|
||||
id: 2
|
||||
5
test/fixtures/contract_processes.yml
vendored
Normal file
5
test/fixtures/contract_processes.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
one:
|
||||
id: 1
|
||||
two:
|
||||
id: 2
|
||||
5
test/fixtures/contract_statuses.yml
vendored
Normal file
5
test/fixtures/contract_statuses.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
one:
|
||||
id: 1
|
||||
two:
|
||||
id: 2
|
||||
5
test/fixtures/contracts.yml
vendored
Normal file
5
test/fixtures/contracts.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
one:
|
||||
id: 1
|
||||
two:
|
||||
id: 2
|
||||
10
test/unit/contract_category_test.rb
Normal file
10
test/unit/contract_category_test.rb
Normal file
@ -0,0 +1,10 @@
|
||||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class ContractCategoryTest < ActiveSupport::TestCase
|
||||
fixtures :contract_categories
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
10
test/unit/contract_custom_field_test.rb
Normal file
10
test/unit/contract_custom_field_test.rb
Normal file
@ -0,0 +1,10 @@
|
||||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class ContractCustomFieldTest < ActiveSupport::TestCase
|
||||
fixtures :contract_custom_fields
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
10
test/unit/contract_note_test.rb
Normal file
10
test/unit/contract_note_test.rb
Normal file
@ -0,0 +1,10 @@
|
||||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class ContractNoteTest < ActiveSupport::TestCase
|
||||
fixtures :contract_notes
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
10
test/unit/contract_process_test.rb
Normal file
10
test/unit/contract_process_test.rb
Normal file
@ -0,0 +1,10 @@
|
||||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class ContractProcessTest < ActiveSupport::TestCase
|
||||
fixtures :contract_processes
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
10
test/unit/contract_status_test.rb
Normal file
10
test/unit/contract_status_test.rb
Normal file
@ -0,0 +1,10 @@
|
||||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class ContractStatusTest < ActiveSupport::TestCase
|
||||
fixtures :contract_statuses
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
10
test/unit/contracts_test.rb
Normal file
10
test/unit/contracts_test.rb
Normal file
@ -0,0 +1,10 @@
|
||||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class ContractsTest < ActiveSupport::TestCase
|
||||
fixtures :contracts
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user