fat_free_crm 0.11.3 → 0.11.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fat_free_crm might be problematic. Click here for more details.
- data/.gitignore +1 -0
- data/.travis.yml +2 -2
- data/CHANGELOG +6 -1
- data/CONTRIBUTORS +40 -1
- data/Capfile +5 -0
- data/Gemfile +25 -6
- data/Gemfile.lock +128 -86
- data/README.md +23 -16
- data/{vendor → app}/assets/images/delete.png +0 -0
- data/app/assets/javascripts/admin/fields.js.coffee +62 -0
- data/app/assets/javascripts/application.js.erb +8 -1
- data/app/assets/javascripts/crm.js +44 -46
- data/app/assets/javascripts/crm_chosen.js.coffee +10 -7
- data/app/assets/javascripts/datepicker.js.coffee +15 -0
- data/app/assets/javascripts/format_buttons.js.coffee +48 -0
- data/app/assets/javascripts/{admin/field_groups.js.coffee → groups.js.coffee} +0 -0
- data/app/assets/javascripts/lists.js.coffee +1 -1
- data/app/assets/javascripts/search.js.coffee +56 -38
- data/app/assets/stylesheets/admin/{field_groups.css.scss → fields.css.scss} +4 -0
- data/app/assets/stylesheets/advanced_search.css.scss +79 -0
- data/app/assets/stylesheets/application.css.erb +4 -0
- data/app/assets/stylesheets/base.scss +3 -3
- data/app/assets/stylesheets/common.scss +72 -25
- data/app/assets/stylesheets/fields.scss +14 -0
- data/app/assets/stylesheets/format_buttons.css.scss +30 -0
- data/app/assets/stylesheets/groups.css.scss +3 -0
- data/app/assets/stylesheets/header.scss +7 -6
- data/{vendor/plugins/.gitkeep → app/assets/stylesheets/index_headers.css.scss} +0 -0
- data/app/assets/stylesheets/print.css.scss +12 -3
- data/app/assets/stylesheets/rails.scss +12 -3
- data/app/controllers/admin/application_controller.rb +1 -1
- data/app/controllers/admin/field_groups_controller.rb +2 -0
- data/app/controllers/admin/fields_controller.rb +41 -17
- data/app/controllers/admin/groups_controller.rb +70 -0
- data/app/controllers/admin/tags_controller.rb +1 -0
- data/app/controllers/admin/users_controller.rb +8 -7
- data/app/controllers/application_controller.rb +34 -5
- data/app/controllers/comments_controller.rb +2 -3
- data/app/controllers/entities/accounts_controller.rb +30 -37
- data/app/controllers/entities/campaigns_controller.rb +56 -29
- data/app/controllers/entities/contacts_controller.rb +24 -26
- data/app/controllers/entities/leads_controller.rb +38 -37
- data/app/controllers/entities/opportunities_controller.rb +28 -34
- data/app/controllers/entities_controller.rb +71 -43
- data/app/controllers/home_controller.rb +29 -27
- data/app/controllers/tasks_controller.rb +18 -17
- data/app/controllers/users_controller.rb +12 -8
- data/app/helpers/accounts_helper.rb +58 -16
- data/app/helpers/addresses_helper.rb +4 -1
- data/app/helpers/admin/fields_helper.rb +3 -4
- data/app/helpers/application_helper.rb +147 -100
- data/app/helpers/campaigns_helper.rb +2 -9
- data/app/helpers/fields_helper.rb +0 -1
- data/app/helpers/groups_helper.rb +2 -0
- data/app/helpers/home_helper.rb +11 -0
- data/app/helpers/leads_helper.rb +2 -9
- data/app/helpers/opportunities_helper.rb +2 -9
- data/app/helpers/{crm_tags_helper.rb → tags_helper.rb} +9 -8
- data/app/helpers/tasks_helper.rb +5 -21
- data/app/helpers/users_helper.rb +14 -7
- data/app/helpers/versions_helper.rb +46 -0
- data/app/inputs/date_time_input.rb +8 -25
- data/app/inputs/datepair_input.rb +77 -0
- data/app/inputs/datetimepair_input.rb +37 -0
- data/app/mailers/user_mailer.rb +10 -0
- data/app/models/entities/account.rb +18 -11
- data/app/models/entities/account_contact.rb +4 -3
- data/app/models/entities/account_opportunity.rb +0 -1
- data/app/models/entities/campaign.rb +6 -7
- data/app/models/entities/contact.rb +53 -25
- data/app/models/entities/contact_opportunity.rb +0 -1
- data/app/models/entities/lead.rb +24 -13
- data/app/models/entities/opportunity.rb +34 -16
- data/app/models/fields/custom_field.rb +29 -13
- data/app/models/fields/custom_field_date_pair.rb +58 -0
- data/app/models/fields/custom_field_datetime_pair.rb +28 -0
- data/app/models/fields/custom_field_pair.rb +54 -0
- data/app/models/fields/field.rb +60 -43
- data/app/models/fields/field_group.rb +0 -9
- data/app/models/observers/entity_observer.rb +29 -0
- data/app/models/observers/opportunity_observer.rb +3 -0
- data/app/models/polymorphic/address.rb +14 -0
- data/app/models/polymorphic/avatar.rb +13 -1
- data/app/models/polymorphic/email.rb +1 -1
- data/app/models/polymorphic/task.rb +14 -13
- data/app/models/setting.rb +14 -21
- data/app/models/users/ability.rb +25 -4
- data/app/models/users/group.rb +13 -0
- data/app/models/users/permission.rb +3 -1
- data/app/models/users/preference.rb +1 -2
- data/app/models/users/user.rb +25 -3
- data/app/views/accounts/_account.html.haml +5 -39
- data/app/views/accounts/_edit.html.haml +3 -2
- data/app/views/accounts/_index_brief.html.haml +32 -0
- data/app/views/accounts/_index_long.html.haml +42 -0
- data/app/views/accounts/_new.html.haml +3 -2
- data/app/views/accounts/_sidebar_index.html.haml +3 -4
- data/app/views/accounts/_sidebar_show.html.haml +2 -2
- data/app/views/accounts/_title_bar.html.haml +11 -0
- data/app/views/accounts/_top_section.html.haml +1 -1
- data/app/views/accounts/create.js.rjs +1 -2
- data/app/views/accounts/destroy.js.rjs +1 -1
- data/app/views/accounts/edit.js.rjs +0 -2
- data/app/views/accounts/index.html.haml +6 -13
- data/app/views/accounts/index.js.rjs +3 -1
- data/app/views/accounts/index.xls.builder +82 -0
- data/app/views/accounts/new.js.rjs +0 -2
- data/app/views/accounts/show.html.haml +17 -15
- data/app/views/accounts/show.js.erb +2 -0
- data/app/views/admin/custom_fields/_base_field.html.haml +21 -0
- data/app/views/admin/custom_fields/_check_boxes_field.html.haml +6 -0
- data/app/views/admin/custom_fields/_date_field.html.haml +14 -0
- data/app/views/admin/custom_fields/_date_pair_field.html.haml +21 -0
- data/app/views/admin/custom_fields/_datetime_field.html.haml +14 -0
- data/app/views/admin/custom_fields/_datetime_pair_field.html.haml +21 -0
- data/app/views/admin/custom_fields/_radio_field.html.haml +6 -0
- data/app/views/admin/custom_fields/_select_field.html.haml +25 -0
- data/app/views/admin/custom_fields/_string_field.html.haml +2 -0
- data/app/views/admin/field_groups/_field_group.html.haml +7 -5
- data/app/views/admin/field_groups/_top_section.html.haml +4 -3
- data/app/views/admin/field_groups/create.js.rjs +1 -2
- data/app/views/admin/fields/_field.html.haml +5 -3
- data/app/views/admin/fields/_form.html.haml +35 -0
- data/app/views/admin/fields/_subform.html.haml +6 -0
- data/app/views/admin/fields/create.js.erb +19 -0
- data/app/views/admin/fields/destroy.js.erb +9 -0
- data/app/views/admin/fields/edit.js.erb +1 -0
- data/app/views/admin/fields/index.html.haml +11 -8
- data/app/views/admin/fields/update.js.erb +13 -0
- data/app/views/admin/groups/_edit.html.haml +12 -0
- data/app/views/admin/groups/_form.html.haml +13 -0
- data/app/views/admin/groups/_group.html.haml +15 -0
- data/app/views/admin/groups/_new.html.haml +12 -0
- data/app/views/admin/groups/create.js.rjs +11 -0
- data/app/views/admin/{fields → groups}/destroy.js.rjs +3 -3
- data/app/views/admin/groups/edit.js.rjs +21 -0
- data/app/views/admin/groups/index.html.haml +18 -0
- data/app/views/admin/groups/index.js.rjs +2 -0
- data/app/views/admin/groups/new.js.rjs +9 -0
- data/app/views/admin/groups/show.html.haml +11 -0
- data/app/views/admin/groups/update.js.rjs +10 -0
- data/app/views/admin/users/_profile.html.haml +13 -1
- data/app/views/admin/users/_user.html.haml +7 -2
- data/app/views/admin/users/index.js.rjs +1 -0
- data/app/views/application/index.atom.builder +1 -1
- data/app/views/application/index.rss.builder +1 -1
- data/app/views/application/show.atom.builder +32 -0
- data/app/views/application/show.rss.builder +29 -0
- data/app/views/campaigns/_campaign.html.haml +5 -21
- data/app/views/campaigns/_edit.html.haml +3 -2
- data/app/views/campaigns/_index_brief.html.haml +15 -0
- data/app/views/campaigns/_index_long.html.haml +20 -0
- data/app/views/campaigns/_new.html.haml +4 -2
- data/app/views/campaigns/_sidebar_index.html.haml +3 -3
- data/app/views/campaigns/_title_bar.html.haml +11 -0
- data/app/views/campaigns/_top_section.html.haml +2 -2
- data/app/views/campaigns/create.js.rjs +1 -4
- data/app/views/campaigns/destroy.js.rjs +1 -1
- data/app/views/campaigns/edit.js.rjs +0 -4
- data/app/views/campaigns/index.html.haml +6 -13
- data/app/views/campaigns/index.js.rjs +3 -1
- data/app/views/campaigns/index.xls.builder +75 -0
- data/app/views/campaigns/new.js.rjs +0 -4
- data/app/views/campaigns/show.html.haml +17 -15
- data/app/views/campaigns/show.js.erb +2 -0
- data/app/views/campaigns/update.js.rjs +0 -2
- data/app/views/comments/_comment.html.haml +6 -5
- data/app/views/comments/_edit.html.haml +5 -5
- data/app/views/comments/_new.html.haml +6 -5
- data/app/views/comments/create.js.rjs +1 -1
- data/app/views/contacts/_contact.html.haml +5 -52
- data/app/views/contacts/_contacts.html.haml +1 -0
- data/app/views/contacts/_edit.html.haml +3 -2
- data/app/views/contacts/_index_brief.html.haml +25 -0
- data/app/views/contacts/_index_full.html.haml +57 -0
- data/app/views/contacts/_index_long.html.haml +43 -0
- data/app/views/contacts/_new.html.haml +4 -2
- data/app/views/contacts/_section_extra.html.haml +26 -0
- data/app/views/contacts/_section_general.html.haml +22 -0
- data/app/views/contacts/_sidebar_index.html.haml +0 -3
- data/app/views/contacts/_sidebar_show.html.haml +2 -10
- data/app/views/contacts/_title_bar.html.haml +11 -0
- data/app/views/contacts/_top_section.html.haml +1 -1
- data/app/views/contacts/create.js.rjs +1 -2
- data/app/views/contacts/destroy.js.rjs +1 -1
- data/app/views/contacts/edit.js.rjs +0 -2
- data/app/views/contacts/index.html.haml +6 -14
- data/app/views/contacts/index.js.rjs +3 -1
- data/app/views/contacts/index.xls.builder +102 -0
- data/app/views/contacts/new.js.rjs +0 -2
- data/app/views/contacts/show.html.haml +15 -15
- data/app/views/contacts/show.js.erb +2 -0
- data/app/views/entities/_basic_search.html.haml +22 -0
- data/app/views/entities/_permissions.html.haml +41 -0
- data/app/views/entities/_search.html.haml +15 -0
- data/app/views/entities/_section_custom_fields.html.haml +11 -0
- data/app/views/entities/_title_bar.html.haml +12 -0
- data/app/views/entities/attach.js.rjs +1 -1
- data/app/views/entities/opportunities.js.rjs +1 -1
- data/app/views/entities/versions.js.erb +3 -0
- data/app/views/fields/_edit_custom_field_group.html.haml +8 -0
- data/app/views/fields/_group.html.haml +11 -20
- data/app/views/fields/_group_table.html.haml +13 -0
- data/app/views/fields/_group_view.html.haml +7 -0
- data/app/views/fields/_groups.html.haml +1 -4
- data/app/views/fields/_sidebar_show.html.haml +5 -4
- data/app/views/home/_account.html.haml +29 -0
- data/app/views/home/_activity.html.haml +16 -6
- data/app/views/home/_opportunity.html.haml +41 -0
- data/app/views/home/_options.html.haml +1 -1
- data/app/views/home/_task.html.haml +46 -0
- data/app/views/home/index.html.haml +32 -1
- data/app/views/home/index.js.rjs +1 -0
- data/app/views/layouts/_header.html.haml +3 -3
- data/app/views/layouts/_sidebar.html.haml +1 -3
- data/app/views/layouts/_tabbed.html.haml +2 -3
- data/app/views/layouts/_tabless.html.haml +1 -1
- data/app/views/layouts/admin/_header.html.haml +1 -1
- data/app/views/layouts/application.html.haml +7 -8
- data/app/views/layouts/header.xls.builder +8 -0
- data/app/views/leads/_contact.html.haml +1 -2
- data/app/views/leads/_convert.html.haml +1 -2
- data/app/views/leads/_convert_permissions.html.haml +21 -11
- data/app/views/leads/_edit.html.haml +3 -2
- data/app/views/leads/_index_brief.html.haml +41 -0
- data/app/views/leads/_index_long.html.haml +62 -0
- data/app/views/leads/_lead.html.haml +5 -62
- data/app/views/leads/_new.html.haml +4 -2
- data/app/views/leads/_opportunity.html.haml +1 -1
- data/app/views/leads/_sidebar_index.html.haml +3 -3
- data/app/views/leads/_sidebar_show.html.haml +3 -3
- data/app/views/leads/_status.html.haml +1 -1
- data/app/views/leads/_title_bar.html.haml +16 -0
- data/app/views/leads/convert.js.rjs +0 -1
- data/app/views/leads/create.js.rjs +1 -2
- data/app/views/leads/destroy.js.rjs +1 -1
- data/app/views/leads/edit.js.rjs +0 -2
- data/app/views/leads/index.html.haml +6 -13
- data/app/views/leads/index.js.rjs +3 -1
- data/app/views/leads/index.xls.builder +100 -0
- data/app/views/leads/new.js.rjs +0 -2
- data/app/views/leads/promote.js.rjs +0 -1
- data/app/views/leads/show.html.haml +13 -18
- data/app/views/leads/show.js.erb +2 -0
- data/app/views/{shared/_lists.html.haml → lists/_sidebar.html.haml} +0 -0
- data/app/views/lists/create.js.rjs +1 -1
- data/app/views/opportunities/_edit.html.haml +3 -2
- data/app/views/opportunities/_index_brief.html.haml +29 -0
- data/app/views/opportunities/_index_long.html.haml +59 -0
- data/app/views/opportunities/_new.html.haml +4 -2
- data/app/views/opportunities/_opportunity.html.haml +5 -57
- data/app/views/opportunities/_sidebar_index.html.haml +3 -3
- data/app/views/opportunities/_sidebar_show.html.haml +2 -2
- data/app/views/opportunities/_title_bar.html.haml +11 -0
- data/app/views/opportunities/_top_section.html.haml +2 -2
- data/app/views/opportunities/create.js.rjs +4 -6
- data/app/views/opportunities/destroy.js.rjs +1 -1
- data/app/views/opportunities/edit.js.rjs +0 -3
- data/app/views/opportunities/index.html.haml +6 -14
- data/app/views/opportunities/index.js.rjs +3 -1
- data/app/views/opportunities/index.xls.builder +69 -0
- data/app/views/opportunities/new.js.rjs +1 -5
- data/app/views/opportunities/show.html.haml +14 -14
- data/app/views/opportunities/show.js.erb +2 -0
- data/app/views/opportunities/update.js.rjs +0 -1
- data/app/views/passwords/new.html.haml +1 -1
- data/app/views/shared/_add_comment.html.haml +8 -0
- data/app/views/shared/_address.html.haml +1 -1
- data/app/views/shared/_address_show.html.haml +1 -1
- data/app/views/shared/_edit_comment.html.haml +2 -2
- data/app/views/shared/_export.html.haml +2 -1
- data/app/views/shared/_paginate_with_per_page.html.haml +14 -0
- data/app/views/shared/_recently.html.haml +1 -1
- data/app/views/shared/_search.html.haml +1 -1
- data/app/views/shared/_tags.html.haml +1 -2
- data/app/views/shared/_tasks.html.haml +2 -2
- data/app/views/tasks/_completed.html.haml +3 -3
- data/app/views/tasks/_new.html.haml +1 -1
- data/app/views/tasks/_pending.html.haml +2 -3
- data/app/views/tasks/_sidebar_index.html.haml +2 -2
- data/app/views/tasks/_top_section.html.haml +5 -3
- data/app/views/tasks/create.js.rjs +3 -4
- data/app/views/tasks/edit.js.rjs +2 -4
- data/app/views/tasks/index.html.haml +1 -1
- data/app/views/tasks/index.xls.builder +47 -0
- data/app/views/tasks/new.js.rjs +0 -2
- data/app/views/tasks/update.js.rjs +0 -1
- data/app/views/user_mailer/assigned_entity_notification.html.haml +3 -0
- data/app/views/users/_user.html.haml +2 -2
- data/app/views/users/_user_report.html.haml +6 -0
- data/app/views/users/opportunities_overview.html.haml +16 -0
- data/app/views/users/show.html.haml +2 -3
- data/app/views/users/update.js.rjs +1 -1
- data/app/views/versions/_version.html.haml +4 -19
- data/app/views/versions/_version_item.html.haml +8 -0
- data/app/views/versions/_versions.html.haml +9 -9
- data/config/application.rb +10 -2
- data/config/deploy.example.rb +47 -0
- data/config/environments/development.rb +1 -0
- data/config/environments/production.rb +1 -3
- data/config/environments/staging.rb +1 -1
- data/config/initializers/action_mailer.rb +10 -8
- data/config/initializers/custom_fields.rb +21 -0
- data/config/initializers/gravatar.rb +7 -0
- data/config/initializers/paper_trail.rb +1 -0
- data/config/initializers/ransack.rb +15 -0
- data/config/initializers/simple_form.rb +1 -2
- data/config/initializers/views.rb +42 -0
- data/config/locales/cz_fat_free_crm.yml +0 -10
- data/config/locales/de_fat_free_crm.yml +23 -21
- data/config/locales/en-GB_fat_free_crm.yml +241 -25
- data/config/locales/en-US_fat_free_crm.yml +139 -57
- data/config/locales/en-US_ransack.yml +92 -0
- data/config/locales/es_fat_free_crm.yml +0 -6
- data/config/locales/fr-CA_fat_free_crm.yml +0 -6
- data/config/locales/fr_fat_free_crm.yml +3 -14
- data/config/locales/it_fat_free_crm.yml +0 -11
- data/config/locales/ja_fat_free_crm.yml +0 -10
- data/config/locales/pl_fat_free_crm.yml +0 -6
- data/config/locales/pt-BR_fat_free_crm.yml +0 -6
- data/config/locales/ru_fat_free_crm.yml +0 -9
- data/config/locales/sv-SE_fat_free_crm.yml +0 -10
- data/config/locales/th_fat_free_crm.yml +0 -6
- data/config/locales/zh-CN.yml +4 -0
- data/config/locales/zh-CN_fat_free_crm.yml +78 -47
- data/config/routes.rb +13 -0
- data/config/settings.default.yml +20 -20
- data/db/demo/addresses.yml +2 -2
- data/db/migrate/20100928030598_create_sessions.rb +5 -0
- data/db/migrate/20100928030627_acts_as_taggable_on_migration.rb +6 -6
- data/db/migrate/20111201030535_add_field_groups_klass_name.rb +2 -1
- data/db/migrate/20120406082136_create_groups.rb +19 -0
- data/db/migrate/20120510025219_add_not_null_constraints_for_timestamp_columns.rb +21 -0
- data/db/migrate/20120528102124_increase_length_of_version_events.rb +9 -0
- data/db/migrate/20120801032706_add_pair_id_to_fields.rb +5 -0
- data/db/migrate/20121003063155_add_settings_to_custom_fields.rb +5 -0
- data/db/migrate/20121221033947_fix_country_mapping.rb +32 -0
- data/db/schema.rb +25 -6
- data/fat_free_crm.gemspec +16 -13
- data/lib/fat_free_crm.rb +2 -0
- data/lib/fat_free_crm/comment_extensions.rb +23 -0
- data/lib/fat_free_crm/core_ext/array.rb +8 -2
- data/lib/fat_free_crm/fields.rb +24 -2
- data/lib/fat_free_crm/gem_dependencies.rb +7 -1
- data/lib/fat_free_crm/permissions.rb +47 -26
- data/lib/fat_free_crm/version.rb +1 -1
- data/lib/fat_free_crm/view_factory.rb +95 -0
- data/lib/plugins/country_select/lib/country_select.rb +393 -374
- data/lib/tasks/{plugins.rake → db/migrate.rake} +1 -1
- data/lib/tasks/{schema_upgrade.rake → db/schema.rake} +2 -1
- data/lib/tasks/{mail_processing.rake → ffcrm/comment_replies.rake} +2 -21
- data/lib/tasks/ffcrm/config.rake +33 -0
- data/lib/tasks/{demo.rake → ffcrm/demo.rake} +3 -2
- data/lib/tasks/ffcrm/dropbox.rake +42 -0
- data/lib/tasks/ffcrm/settings.rake +46 -0
- data/lib/tasks/{fat_free_crm.rake → ffcrm/setup.rake} +1 -39
- data/lib/tasks/ffcrm/update_data.rake +256 -0
- data/{acceptance → spec/acceptance}/acceptance_helper.rb +5 -4
- data/{acceptance → spec/acceptance}/accounts_spec.rb +36 -10
- data/spec/acceptance/admin/groups_spec.rb +26 -0
- data/spec/acceptance/admin/users_spec.rb +34 -0
- data/spec/acceptance/campaigns_spec.rb +101 -0
- data/spec/acceptance/contacts_spec.rb +101 -0
- data/spec/acceptance/dashboard_spec.rb +62 -0
- data/spec/acceptance/leads_spec.rb +109 -0
- data/spec/acceptance/opportunities_overview_spec.rb +82 -0
- data/spec/acceptance/opportunities_spec.rb +103 -0
- data/{acceptance → spec/acceptance}/support/browser.rb +0 -0
- data/{acceptance → spec/acceptance}/support/headless.rb +0 -0
- data/{acceptance → spec/acceptance}/support/helpers.rb +8 -1
- data/{acceptance → spec/acceptance}/support/maintain_sessions.rb +0 -0
- data/spec/acceptance/support/paths.rb +42 -0
- data/spec/acceptance/support/selector_helpers.rb +31 -0
- data/spec/acceptance/tasks_spec.rb +85 -0
- data/spec/controllers/admin/groups_controller_spec.rb +5 -0
- data/spec/controllers/admin/users_controller_spec.rb +2 -3
- data/spec/controllers/applications_controller_spec.rb +40 -0
- data/spec/controllers/comments_controller_spec.rb +5 -6
- data/spec/controllers/emails_controller_spec.rb +1 -2
- data/spec/controllers/entities/accounts_controller_spec.rb +65 -81
- data/spec/controllers/entities/campaigns_controller_spec.rb +69 -85
- data/spec/controllers/entities/contacts_controller_spec.rb +78 -95
- data/spec/controllers/entities/leads_controller_spec.rb +105 -127
- data/spec/controllers/entities/opportunities_controller_spec.rb +88 -103
- data/spec/controllers/entities_controller_spec.rb +39 -0
- data/spec/controllers/home_controller_spec.rb +101 -11
- data/spec/controllers/tasks_controller_spec.rb +27 -32
- data/spec/controllers/users_controller_spec.rb +95 -28
- data/spec/factories/account_factories.rb +2 -2
- data/spec/factories/opportunity_factories.rb +12 -4
- data/spec/factories/task_factories.rb +4 -0
- data/spec/factories/user_factories.rb +9 -2
- data/spec/helpers/application_helper_spec.rb +15 -1
- data/spec/helpers/groups_helper_spec.rb +15 -0
- data/spec/helpers/users_helper_spec.rb +26 -4
- data/spec/lib/comment_extensions_spec.rb +29 -0
- data/spec/lib/core_ext/{string.rb → string_spec.rb} +0 -1
- data/spec/lib/fields_spec.rb +104 -0
- data/spec/lib/permissions_spec.rb +144 -0
- data/spec/lib/view_factory_spec.rb +68 -0
- data/spec/mailers/subscription_mailer_spec.rb +18 -4
- data/spec/mailers/user_mailer_spec.rb +134 -0
- data/spec/models/entities/account_spec.rb +44 -4
- data/spec/models/entities/campaign_spec.rb +3 -4
- data/spec/models/entities/contact_spec.rb +45 -5
- data/spec/models/entities/lead_spec.rb +3 -4
- data/spec/models/entities/opportunity_spec.rb +105 -9
- data/spec/models/fields/custom_field_date_pair_spec.rb +106 -0
- data/spec/models/fields/custom_field_pair_spec.rb +94 -0
- data/spec/models/fields/custom_field_spec.rb +43 -23
- data/spec/models/fields/field_spec.rb +3 -5
- data/spec/models/observers/entity_observer_spec.rb +65 -0
- data/spec/models/polymorphic/task_spec.rb +74 -118
- data/spec/models/polymorphic/version_spec.rb +18 -18
- data/spec/models/users/group_spec.rb +5 -0
- data/spec/models/users/permission_spec.rb +18 -1
- data/spec/models/users/preference_spec.rb +5 -1
- data/spec/models/users/user_spec.rb +55 -8
- data/spec/shared/models.rb +54 -0
- data/spec/spec_helper.rb +82 -87
- data/spec/support/auth_macros.rb +2 -3
- data/spec/views/accounts/_edit.haml_spec.rb +1 -2
- data/spec/views/accounts/_new.haml_spec.rb +1 -2
- data/spec/views/accounts/create.rjs_spec.rb +1 -3
- data/spec/views/accounts/edit.rjs_spec.rb +3 -4
- data/spec/views/accounts/index.haml_spec.rb +9 -6
- data/spec/views/accounts/new.rjs_spec.rb +2 -9
- data/spec/views/accounts/show.haml_spec.rb +1 -2
- data/spec/views/accounts/update.rjs_spec.rb +2 -3
- data/spec/views/admin/users/_create.haml_spec.rb +1 -2
- data/spec/views/admin/users/create.rjs_spec.rb +1 -2
- data/spec/views/campaigns/_edit.haml_spec.rb +2 -3
- data/spec/views/campaigns/_new.haml_spec.rb +2 -3
- data/spec/views/campaigns/create.rjs_spec.rb +0 -3
- data/spec/views/campaigns/destroy.rjs_spec.rb +1 -2
- data/spec/views/campaigns/edit.rjs_spec.rb +3 -6
- data/spec/views/campaigns/index.haml_spec.rb +6 -3
- data/spec/views/campaigns/new.rjs_spec.rb +2 -13
- data/spec/views/campaigns/show.haml_spec.rb +4 -6
- data/spec/views/campaigns/update.rjs_spec.rb +2 -7
- data/spec/views/contacts/_edit.haml_spec.rb +6 -7
- data/spec/views/contacts/_new.haml_spec.rb +2 -3
- data/spec/views/contacts/create.rjs_spec.rb +1 -3
- data/spec/views/contacts/edit.rjs_spec.rb +3 -4
- data/spec/views/contacts/index.haml_spec.rb +6 -3
- data/spec/views/contacts/new.rjs_spec.rb +2 -11
- data/spec/views/contacts/show.haml_spec.rb +1 -2
- data/spec/views/contacts/update.rjs_spec.rb +2 -3
- data/spec/views/home/index.haml_spec.rb +6 -2
- data/spec/views/home/index.rjs_spec.rb +1 -2
- data/spec/views/home/options.rjs_spec.rb +1 -2
- data/spec/views/leads/_convert.haml_spec.rb +1 -2
- data/spec/views/leads/_edit.haml_spec.rb +2 -3
- data/spec/views/leads/_new.haml_spec.rb +2 -3
- data/spec/views/leads/_sidebar_show.haml_spec.rb +1 -2
- data/spec/views/leads/convert.rjs_spec.rb +3 -5
- data/spec/views/leads/edit.rjs_spec.rb +4 -5
- data/spec/views/leads/index.haml_spec.rb +6 -3
- data/spec/views/leads/new.rjs_spec.rb +2 -11
- data/spec/views/leads/promote.rjs_spec.rb +3 -5
- data/spec/views/leads/show.haml_spec.rb +1 -2
- data/spec/views/leads/update.rjs_spec.rb +2 -3
- data/spec/views/opportunities/_edit.haml_spec.rb +5 -6
- data/spec/views/opportunities/_new.haml_spec.rb +2 -4
- data/spec/views/opportunities/create.rjs_spec.rb +0 -2
- data/spec/views/opportunities/edit.rjs_spec.rb +3 -4
- data/spec/views/opportunities/index.haml_spec.rb +7 -4
- data/spec/views/opportunities/new.rjs_spec.rb +2 -12
- data/spec/views/opportunities/show.haml_spec.rb +1 -2
- data/spec/views/opportunities/update.rjs_spec.rb +2 -3
- data/spec/views/tasks/_edit.haml_spec.rb +1 -3
- data/spec/views/tasks/complete.rjs_spec.rb +2 -3
- data/spec/views/tasks/create.rjs_spec.rb +2 -2
- data/spec/views/tasks/edit.rjs_spec.rb +1 -2
- data/spec/views/tasks/new.rjs_spec.rb +1 -18
- data/spec/views/users/avatar.rjs_spec.rb +1 -2
- data/spec/views/users/change_password.rjs_spec.rb +1 -2
- data/spec/views/users/edit.rjs_spec.rb +1 -2
- data/spec/views/users/password.rjs_spec.rb +1 -1
- data/spec/views/users/update.rjs_spec.rb +1 -2
- data/spec/views/users/upload_avatar.rjs_spec.rb +6 -7
- data/vendor/assets/images/brief.png +0 -0
- data/vendor/assets/images/chosen-sprite.png +0 -0
- data/vendor/assets/images/full.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_flat_0_eeeeee_40x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_flat_100_ffffff_40x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_flat_25_3875d7_40x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_flat_55_ffffff_40x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_flat_65_3875d7_40x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_highlight-soft_50_dddddd_1x100.png +0 -0
- data/vendor/assets/images/jquery-ui/{ui-icons_ef8c08_256x240.png → ui-icons_0073ea_256x240.png} +0 -0
- data/vendor/assets/images/jquery-ui/ui-icons_466bb1_256x240.png +0 -0
- data/vendor/assets/images/jquery-ui/{ui-icons_ffd27a_256x240.png → ui-icons_ff0084_256x240.png} +0 -0
- data/vendor/assets/images/long.png +0 -0
- data/vendor/assets/javascripts/chosen-jquery.js +3 -0
- data/vendor/assets/javascripts/chosen-prototype.js +3 -0
- data/vendor/assets/javascripts/chosen.jquery.coffee +574 -0
- data/vendor/assets/javascripts/chosen.proto.coffee +580 -0
- data/vendor/assets/javascripts/jquery.disable.js +23 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-addon.js +1882 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-af.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-ca.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-cz.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-de.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-el.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-es.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-et.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-fi.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-fr-CA.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-fr.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-gl.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-he.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-hu.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-id.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-it.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-ja.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-ko.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-lt.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-nl.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-no.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-pl.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-pt.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-ro.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-ru.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-sk.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-sv.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-tr.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-vi.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-zh-CN.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery-ui-timepicker-zh-TW.js +20 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery.ui.datepicker-cz.js +23 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery.ui.datepicker-de.js +23 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery.ui.datepicker-en-GB.js +23 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery.ui.datepicker-es.js +23 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery.ui.datepicker-fr.js +23 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery.ui.datepicker-it.js +23 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery.ui.datepicker-ja.js +23 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery.ui.datepicker-pl.js +23 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery.ui.datepicker-pt-BR.js +23 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery.ui.datepicker-ru.js +23 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery.ui.datepicker-sv-SE.js +23 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery.ui.datepicker-th.js +23 -0
- data/vendor/assets/javascripts/jquery_ui_datepicker/jquery.ui.datepicker-zh-CN.js +23 -0
- data/vendor/assets/javascripts/lib/abstract-chosen.coffee +110 -0
- data/vendor/assets/javascripts/lib/select-parser.coffee +51 -0
- data/vendor/assets/stylesheets/chosen.css.sass +361 -0
- data/vendor/assets/stylesheets/{jquery-ui.custom.css.erb → jquery-ui.custom.css} +70 -70
- data/zeus.json +21 -0
- metadata +304 -140
- data/acceptance/support/database_cleaner.rb +0 -16
- data/acceptance/support/paths.rb +0 -9
- data/app/views/accounts/_options.html.haml +0 -20
- data/app/views/accounts/_permissions.html.haml +0 -24
- data/app/views/accounts/options.js.rjs +0 -10
- data/app/views/admin/fields/_edit.html.haml +0 -9
- data/app/views/admin/fields/_new.html.haml +0 -10
- data/app/views/admin/fields/_options.html.haml +0 -12
- data/app/views/admin/fields/_top_section.html.haml +0 -54
- data/app/views/admin/fields/create.js.rjs +0 -16
- data/app/views/admin/fields/edit.js.rjs +0 -35
- data/app/views/admin/fields/index.js.rjs +0 -6
- data/app/views/admin/fields/new.js.rjs +0 -8
- data/app/views/admin/fields/options.js.rjs +0 -10
- data/app/views/admin/fields/update.js.rjs +0 -17
- data/app/views/campaigns/_options.html.haml +0 -20
- data/app/views/campaigns/_permissions.html.haml +0 -24
- data/app/views/campaigns/options.js.rjs +0 -10
- data/app/views/contacts/_options.html.haml +0 -21
- data/app/views/contacts/_permissions.html.haml +0 -24
- data/app/views/contacts/options.js.rjs +0 -10
- data/app/views/entities/_advanced_search.html.haml +0 -12
- data/app/views/entities/_condition_fields.html.haml +0 -14
- data/app/views/entities/_grouping_fields.html.haml +0 -12
- data/app/views/entities/advanced_search.js.rjs +0 -9
- data/app/views/entities/versions.js.rjs +0 -3
- data/app/views/leads/_options.html.haml +0 -21
- data/app/views/leads/_permissions.html.haml +0 -28
- data/app/views/leads/options.js.rjs +0 -10
- data/app/views/opportunities/_options.html.haml +0 -20
- data/app/views/opportunities/_permissions.html.haml +0 -24
- data/app/views/opportunities/options.js.rjs +0 -10
- data/app/views/shared/_outline.html.haml +0 -9
- data/app/views/shared/_per_page.html.haml +0 -10
- data/app/views/shared/_sort_by.html.haml +0 -10
- data/config/initializers/cancan.rb +0 -151
- data/config/initializers/squeel.rb +0 -5
- data/public/blank_iframe.html +0 -2
- data/spec/views/accounts/options.rjs_spec.rb +0 -59
- data/spec/views/campaigns/options.rjs_spec.rb +0 -60
- data/spec/views/contacts/options.rjs_spec.rb +0 -61
- data/spec/views/leads/options.rjs_spec.rb +0 -61
- data/spec/views/opportunities/options.rjs_spec.rb +0 -60
- data/vendor/assets/images/jquery-ui/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_flat_10_000000_40x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-icons_222222_256x240.png +0 -0
- data/vendor/assets/images/jquery-ui/ui-icons_228ef1_256x240.png +0 -0
- data/vendor/assets/javascripts/calendar_date_select/calendar_date_select.js +0 -446
- data/vendor/assets/javascripts/calendar_date_select/format_american.js +0 -35
- data/vendor/assets/javascripts/calendar_date_select/format_danish.js +0 -31
- data/vendor/assets/javascripts/calendar_date_select/format_db.js +0 -27
- data/vendor/assets/javascripts/calendar_date_select/format_euro_24hr.js +0 -7
- data/vendor/assets/javascripts/calendar_date_select/format_euro_24hr_ymd.js +0 -7
- data/vendor/assets/javascripts/calendar_date_select/format_finnish.js +0 -32
- data/vendor/assets/javascripts/calendar_date_select/format_french.js +0 -24
- data/vendor/assets/javascripts/calendar_date_select/format_hyphen_ampm.js +0 -37
- data/vendor/assets/javascripts/calendar_date_select/format_iso_date.js +0 -29
- data/vendor/assets/javascripts/calendar_date_select/format_italian.js +0 -24
- data/vendor/assets/javascripts/calendar_date_select/locale/ar.js +0 -10
- data/vendor/assets/javascripts/calendar_date_select/locale/da.js +0 -11
- data/vendor/assets/javascripts/calendar_date_select/locale/de.js +0 -11
- data/vendor/assets/javascripts/calendar_date_select/locale/es.js +0 -11
- data/vendor/assets/javascripts/calendar_date_select/locale/fi.js +0 -10
- data/vendor/assets/javascripts/calendar_date_select/locale/fr.js +0 -11
- data/vendor/assets/javascripts/calendar_date_select/locale/it.js +0 -9
- data/vendor/assets/javascripts/calendar_date_select/locale/ja.js +0 -11
- data/vendor/assets/javascripts/calendar_date_select/locale/nl.js +0 -11
- data/vendor/assets/javascripts/calendar_date_select/locale/pl.js +0 -11
- data/vendor/assets/javascripts/calendar_date_select/locale/pt.js +0 -11
- data/vendor/assets/javascripts/calendar_date_select/locale/ru.js +0 -10
- data/vendor/assets/javascripts/calendar_date_select/locale/sl.js +0 -11
- data/vendor/assets/javascripts/calendar_date_select/locale/sv.js +0 -9
- data/vendor/assets/stylesheets/calendar_date_select/blue.css +0 -130
- data/vendor/assets/stylesheets/calendar_date_select/default.css +0 -135
- data/vendor/assets/stylesheets/calendar_date_select/green.css +0 -142
- data/vendor/assets/stylesheets/calendar_date_select/plain.css +0 -128
- data/vendor/assets/stylesheets/calendar_date_select/red.css +0 -135
- data/vendor/assets/stylesheets/calendar_date_select/silver.css +0 -133
- data/vendor/plugins/.gitkeep~master +0 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
# Fat Free CRM
|
2
|
+
# Copyright (C) 2008-2011 by Michael Dvorkin
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
class CustomFieldDatePair < CustomFieldPair
|
19
|
+
|
20
|
+
# Register this CustomField with the application
|
21
|
+
#------------------------------------------------------------------------------
|
22
|
+
register(:as => 'date_pair', :klass => 'CustomFieldDatePair', :type => 'date')
|
23
|
+
|
24
|
+
# For rendering paired values
|
25
|
+
# Handle case where both pairs are blank
|
26
|
+
#------------------------------------------------------------------------------
|
27
|
+
def render_value(object)
|
28
|
+
return "" unless paired_with.present?
|
29
|
+
from = render(object.send(name))
|
30
|
+
to = render(object.send(paired_with.name))
|
31
|
+
if from.present? and to.present?
|
32
|
+
I18n.t('pair.from_to', :from => from, :to => to)
|
33
|
+
elsif from.present? and !to.present?
|
34
|
+
I18n.t('pair.from_only', :from => from)
|
35
|
+
elsif !from.present? and to.present?
|
36
|
+
I18n.t('pair.to_only', :to => to)
|
37
|
+
else
|
38
|
+
""
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def render(value)
|
43
|
+
value && value.strftime(I18n.t("date.formats.mmddyy"))
|
44
|
+
end
|
45
|
+
|
46
|
+
def custom_validator(obj)
|
47
|
+
super
|
48
|
+
# validate when we get to 2nd of the pair
|
49
|
+
if pair_id.present?
|
50
|
+
start = CustomFieldPair.find(pair_id)
|
51
|
+
return if start.nil?
|
52
|
+
from = obj.send(start.name)
|
53
|
+
to = obj.send(name)
|
54
|
+
obj.errors.add(name.to_sym, ::I18n.t('activerecord.errors.models.custom_field.endbeforestart', :field => start.label)) if from.present? and to.present? and (from > to)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Fat Free CRM
|
2
|
+
# Copyright (C) 2008-2011 by Michael Dvorkin
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
class CustomFieldDatetimePair < CustomFieldDatePair
|
19
|
+
|
20
|
+
# Register this CustomField with the application
|
21
|
+
#------------------------------------------------------------------------------
|
22
|
+
register(:as => 'datetime_pair', :klass => 'CustomFieldDatetimePair', :type => 'timestamp')
|
23
|
+
|
24
|
+
def render(value)
|
25
|
+
value && value.strftime(I18n.t("time.formats.mmddhhss"))
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Fat Free CRM
|
2
|
+
# Copyright (C) 2008-2011 by Michael Dvorkin
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
class CustomFieldPair < CustomField
|
19
|
+
|
20
|
+
has_one :pair, :class_name => CustomFieldPair, :foreign_key => 'pair_id', :dependent => :destroy # points to 'end'
|
21
|
+
|
22
|
+
# Helper to create a pair. Used in fields_controller
|
23
|
+
#------------------------------------------------------------------------------
|
24
|
+
def self.create_pair(params)
|
25
|
+
fields = params['field']
|
26
|
+
as = params['field']['as']
|
27
|
+
pair = params.delete('pair')
|
28
|
+
base_params = fields.delete_if{|k,v| !%w(field_group_id label as).include?(k)}
|
29
|
+
klass = ("custom_field_" + as.gsub('pair', '_pair')).classify.constantize
|
30
|
+
field1 = klass.create( base_params.merge(pair['0']) )
|
31
|
+
field2 = klass.create( base_params.merge(pair['1']).merge('pair_id' => field1.id, 'required' => field1.required, 'disabled' => field1.disabled) )
|
32
|
+
[field1, field2]
|
33
|
+
end
|
34
|
+
|
35
|
+
# Helper to update a pair. Used in fields_controller
|
36
|
+
#------------------------------------------------------------------------------
|
37
|
+
def self.update_pair(params)
|
38
|
+
fields = params['field']
|
39
|
+
pair = params.delete('pair')
|
40
|
+
base_params = fields.delete_if{|k,v| !%w(field_group_id label as).include?(k)}
|
41
|
+
field1 = CustomFieldPair.find(params['id'])
|
42
|
+
field1.update_attributes( base_params.merge(pair['0']) )
|
43
|
+
field2 = field1.paired_with
|
44
|
+
field2.update_attributes( base_params.merge(pair['1']).merge('required' => field1.required, 'disabled' => field1.disabled) )
|
45
|
+
[field1, field2]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the field that this field is paired with
|
49
|
+
#------------------------------------------------------------------------------
|
50
|
+
def paired_with
|
51
|
+
pair || CustomFieldPair.where(:pair_id => id).first
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/app/models/fields/field.rb
CHANGED
@@ -23,6 +23,7 @@
|
|
23
23
|
# type :string(255)
|
24
24
|
# field_group_id :integer
|
25
25
|
# position :integer
|
26
|
+
# pair_id :integer
|
26
27
|
# name :string(64)
|
27
28
|
# label :string(128)
|
28
29
|
# hint :string(255)
|
@@ -40,58 +41,48 @@ class Field < ActiveRecord::Base
|
|
40
41
|
acts_as_list
|
41
42
|
|
42
43
|
serialize :collection, Array
|
44
|
+
serialize :settings, HashWithIndifferentAccess
|
43
45
|
|
44
46
|
belongs_to :field_group
|
47
|
+
|
48
|
+
scope :core_fields, where(:type => 'CoreField')
|
49
|
+
scope :custom_fields, where("type != 'CoreField'")
|
50
|
+
scope :without_pairs, where(:pair_id => nil)
|
45
51
|
|
46
52
|
delegate :klass, :klass_name, :klass_name=, :to => :field_group
|
47
53
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
'
|
52
|
-
'
|
53
|
-
'
|
54
|
-
'
|
55
|
-
'
|
56
|
-
'
|
57
|
-
'
|
58
|
-
'
|
59
|
-
'
|
60
|
-
'
|
61
|
-
'
|
62
|
-
'
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
validates_presence_of :label, :message => "^Please enter a Field label."
|
68
|
-
validates_length_of :label, :maximum => 64, :message => "^The Field name must be less than 64 characters in length."
|
69
|
-
|
54
|
+
BASE_FIELD_TYPES = {
|
55
|
+
'string' => {:klass => 'CustomField', :type => 'string'},
|
56
|
+
'text' => {:klass => 'CustomField', :type => 'text'},
|
57
|
+
'email' => {:klass => 'CustomField', :type => 'string'},
|
58
|
+
'url' => {:klass => 'CustomField', :type => 'string'},
|
59
|
+
'tel' => {:klass => 'CustomField', :type => 'string'},
|
60
|
+
'select' => {:klass => 'CustomField', :type => 'string'},
|
61
|
+
'radio' => {:klass => 'CustomField', :type => 'string'},
|
62
|
+
'check_boxes' => {:klass => 'CustomField', :type => 'text'},
|
63
|
+
'boolean' => {:klass => 'CustomField', :type => 'boolean'},
|
64
|
+
'date' => {:klass => 'CustomField', :type => 'date'},
|
65
|
+
'datetime' => {:klass => 'CustomField', :type => 'timestamp'},
|
66
|
+
'decimal' => {:klass => 'CustomField', :type => 'decimal', :column_options => {:precision => 15, :scale => 2} },
|
67
|
+
'integer' => {:klass => 'CustomField', :type => 'integer'},
|
68
|
+
'float' => {:klass => 'CustomField', :type => 'float'}
|
69
|
+
}.with_indifferent_access
|
70
|
+
|
71
|
+
validates_presence_of :label, :message => "^Please enter a field label."
|
72
|
+
validates_length_of :label, :maximum => 64, :message => "^The field name must be less than 64 characters in length."
|
70
73
|
validates_numericality_of :maxlength, :only_integer => true, :allow_blank => true, :message => "^Max size can only be whole number."
|
71
|
-
|
72
|
-
|
73
|
-
validates_inclusion_of :as, :in => FIELD_TYPES.keys, :message => "Invalid Field Type."
|
74
|
-
|
75
|
-
|
76
|
-
def self.field_types
|
77
|
-
# Expands concise FIELD_TYPES into a more usable hash
|
78
|
-
@field_types ||= FIELD_TYPES.inject({}) do |hash, n|
|
79
|
-
arr = [n[1]].flatten
|
80
|
-
hash[n[0]] = {:type => arr[0], :options => arr[1]}
|
81
|
-
hash
|
82
|
-
end
|
83
|
-
end
|
74
|
+
validates_presence_of :as, :message => "^Please specify a field type."
|
75
|
+
validates_inclusion_of :as, :in => Proc.new{self.field_types.keys}, :message => "^Invalid field type.", :allow_blank => true
|
84
76
|
|
85
77
|
def column_type(field_type = self.as)
|
86
78
|
(opts = Field.field_types[field_type]) ? opts[:type] : raise("Unknown field_type: #{field_type}")
|
87
79
|
end
|
88
80
|
|
89
81
|
def input_options
|
90
|
-
input_html = {
|
91
|
-
|
82
|
+
input_html = {}
|
92
83
|
attributes.reject { |k,v|
|
93
|
-
!%w(as collection disabled label placeholder required).include?(k) or v.blank?
|
94
|
-
}.symbolize_keys.merge(
|
84
|
+
!%w(as collection disabled label placeholder required maxlength).include?(k) or v.blank?
|
85
|
+
}.symbolize_keys.merge(input_html)
|
95
86
|
end
|
96
87
|
|
97
88
|
def collection_string=(value)
|
@@ -110,15 +101,41 @@ class Field < ActiveRecord::Base
|
|
110
101
|
when 'checkbox'
|
111
102
|
value.to_s == '0' ? "no" : "yes"
|
112
103
|
when 'date'
|
113
|
-
value && value.strftime(I18n.t("date.formats.
|
104
|
+
value && value.strftime(I18n.t("date.formats.mmddyy"))
|
114
105
|
when 'datetime'
|
115
|
-
value && value.strftime(I18n.t("time.formats.
|
106
|
+
value && value.strftime(I18n.t("time.formats.mmddyyyy_hhmm"))
|
116
107
|
when 'check_boxes'
|
117
|
-
value = YAML.load(value) if value.is_a?(String)
|
118
108
|
value.select(&:present?).in_groups_of(2, false).map {|g| g.join(', ')}.join("<br />".html_safe) if Array === value
|
119
109
|
else
|
120
110
|
value.to_s
|
121
111
|
end
|
122
112
|
end
|
123
|
-
end
|
124
113
|
|
114
|
+
protected
|
115
|
+
|
116
|
+
class << self
|
117
|
+
|
118
|
+
# Provides access to registered field_types
|
119
|
+
#------------------------------------------------------------------------------
|
120
|
+
def field_types
|
121
|
+
@@field_types ||= BASE_FIELD_TYPES
|
122
|
+
end
|
123
|
+
|
124
|
+
# Register custom fields so they are available to the rest of the app
|
125
|
+
# Example options: :as => 'datepair', :type => 'date', :klass => 'CustomFieldDatePair'
|
126
|
+
#------------------------------------------------------------------------------
|
127
|
+
def register(options)
|
128
|
+
opts = options.dup
|
129
|
+
as = options.delete(:as)
|
130
|
+
(@@field_types ||= BASE_FIELD_TYPES).merge!(as => options)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns class name given a key
|
134
|
+
#------------------------------------------------------------------------------
|
135
|
+
def lookup_class(as)
|
136
|
+
(@@field_types ||= BASE_FIELD_TYPES)[as][:klass]
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
@@ -49,14 +49,6 @@ class FieldGroup < ActiveRecord::Base
|
|
49
49
|
klass_name.constantize
|
50
50
|
end
|
51
51
|
|
52
|
-
def core_fields
|
53
|
-
fields.where(:type => 'CoreField')
|
54
|
-
end
|
55
|
-
|
56
|
-
def custom_fields
|
57
|
-
fields.where(:type => 'CustomField')
|
58
|
-
end
|
59
|
-
|
60
52
|
def self.with_tags(tag_ids)
|
61
53
|
where 'tag_id IS NULL OR tag_id IN (?)', tag_ids
|
62
54
|
end
|
@@ -78,4 +70,3 @@ class FieldGroup < ActiveRecord::Base
|
|
78
70
|
self.reload
|
79
71
|
end
|
80
72
|
end
|
81
|
-
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class EntityObserver < ActiveRecord::Observer
|
2
|
+
observe :account, :contact, :lead, :opportunity
|
3
|
+
|
4
|
+
def after_create(item)
|
5
|
+
send_notification_to_assignee(item) if current_user != item.assignee
|
6
|
+
end
|
7
|
+
|
8
|
+
def after_update(item)
|
9
|
+
if item.assigned_to_changed? && item.assignee != current_user
|
10
|
+
send_notification_to_assignee(item)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def send_notification_to_assignee(item)
|
17
|
+
UserMailer.assigned_entity_notification(item, current_user).deliver if item.assignee.present? && current_user.present?
|
18
|
+
end
|
19
|
+
|
20
|
+
def current_user
|
21
|
+
# this deals with whodunnit inconsistencies, where in some cases it's set to a user's id and others the user object itself
|
22
|
+
user_id_or_user = PaperTrail.whodunnit
|
23
|
+
if user_id_or_user.is_a?(User)
|
24
|
+
user_id_or_user
|
25
|
+
elsif user_id_or_user.is_a?(String)
|
26
|
+
User.find_by_id(user_id_or_user.to_i)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -35,9 +35,12 @@ class OpportunityObserver < ActiveRecord::Observer
|
|
35
35
|
if original
|
36
36
|
if original.stage != "won" && item.stage == "won" # :other to :won -- add to total campaign revenue.
|
37
37
|
update_campaign_revenue(item.campaign, (item.amount || 0) - (item.discount || 0))
|
38
|
+
item.update_attribute(:probability, 100) # Set probability to 100% if won
|
38
39
|
return log_activity(item, :won)
|
39
40
|
elsif original.stage == "won" && item.stage != "won" # :won to :other -- substract from total campaign revenue.
|
40
41
|
update_campaign_revenue(original.campaign, -((original.amount || 0) - (original.discount || 0)))
|
42
|
+
elsif original.stage != "lost" && item.stage == "lost"
|
43
|
+
item.update_attribute(:probability, 0) # Set probability to 0% if lost
|
41
44
|
end
|
42
45
|
end
|
43
46
|
end
|
@@ -53,4 +53,18 @@ class Address < ActiveRecord::Base
|
|
53
53
|
self.full_address.blank?
|
54
54
|
end
|
55
55
|
end
|
56
|
+
|
57
|
+
#----------------------------------------------------------------------------
|
58
|
+
# Ensure blank address records don't get created. If we have a new record and
|
59
|
+
# address is empty then return true otherwise return false so that _destroy
|
60
|
+
# is processed (if applicable) and the record is removed.
|
61
|
+
# Intended to be called as follows:
|
62
|
+
# accepts_nested_attributes_for :business_address, :allow_destroy => true, :reject_if => proc {|attributes| Address.reject_address(attributes)}
|
63
|
+
def self.reject_address(attributes)
|
64
|
+
exists = attributes['id'].present?
|
65
|
+
empty = %w(street1 street2 city state zipcode country full_address).map{|name| attributes[name].blank?}.all?
|
66
|
+
attributes.merge!({:_destroy => 1}) if exists and empty
|
67
|
+
return (!exists and empty)
|
68
|
+
end
|
69
|
+
|
56
70
|
end
|
@@ -49,5 +49,17 @@ class Avatar < ActiveRecord::Base
|
|
49
49
|
end
|
50
50
|
has_attached_file :image, :styles => STYLES.dup, :url => "/avatars/:entity_type/:id/:style_:filename", :default_url => "/assets/avatar.jpg"
|
51
51
|
|
52
|
-
|
52
|
+
# Convert STYLE symbols to 'w x h' format for Gravatar and Rails
|
53
|
+
# e.g. Avatar.size_from_style(:size => :large) -> '75x75'
|
54
|
+
# Allow options to contain :width and :height override keys
|
55
|
+
#----------------------------------------------------------------------------
|
56
|
+
def self.size_from_style!(options)
|
57
|
+
if options[:width] && options[:height]
|
58
|
+
options[:size] = [:width, :height].map{|d| options[d]}.join("x")
|
59
|
+
elsif Avatar::STYLES.keys.include?(options[:size])
|
60
|
+
options[:size] = Avatar::STYLES[options[:size]].sub(/\#$/,'')
|
61
|
+
end
|
62
|
+
options
|
63
|
+
end
|
53
64
|
|
65
|
+
end
|
@@ -71,6 +71,17 @@ class Task < ActiveRecord::Base
|
|
71
71
|
where('user_id = ? OR assigned_to = ?', user.id, user.id)
|
72
72
|
}
|
73
73
|
|
74
|
+
scope :visible_on_dashboard, lambda { |user|
|
75
|
+
# Show opportunities which either belong to the user and are unassigned, or are assigned to the user
|
76
|
+
where('(user_id = :user_id AND assigned_to IS NULL) OR assigned_to = :user_id', :user_id => user.id).where('completed_at IS NULL')
|
77
|
+
}
|
78
|
+
|
79
|
+
scope :by_due_at, order({
|
80
|
+
"MySQL" => "due_at NOT NULL, due_at ASC",
|
81
|
+
"PostgreSQL" => "due_at ASC NULLS FIRST"
|
82
|
+
}[ActiveRecord::Base.connection.adapter_name] || :due_at)
|
83
|
+
|
84
|
+
|
74
85
|
# Status based scopes to be combined with the due date and completion time.
|
75
86
|
scope :pending, where('completed_at IS NULL').order('tasks.due_at, tasks.id')
|
76
87
|
scope :assigned, where('completed_at IS NULL AND assigned_to IS NOT NULL').order('tasks.due_at, tasks.id')
|
@@ -236,18 +247,8 @@ class Task < ActiveRecord::Base
|
|
236
247
|
|
237
248
|
#----------------------------------------------------------------------------
|
238
249
|
def parse_calendar_date
|
239
|
-
|
240
|
-
|
241
|
-
DateTime.strptime(self.calendar,
|
242
|
-
I18n.t(Setting.task_calendar_with_time ? 'time.formats.mmddyyyy_hhmm' : 'date.formats.mmddyyyy')).utc
|
250
|
+
# always in 2012-10-28 06:28 format regardless of language
|
251
|
+
Time.parse(self.calendar)
|
243
252
|
end
|
244
|
-
|
245
|
-
# Translates month and day names of a given datetime string.
|
246
|
-
#----------------------------------------------------------------------------
|
247
|
-
def translate_month_and_day_names!(date_string)
|
248
|
-
translated = I18n.t([:month_names, :abbr_month_names, :day_names, :abbr_day_names], :scope => :date).flatten.compact
|
249
|
-
original = (Date::MONTHNAMES + Date::ABBR_MONTHNAMES + Date::DAYNAMES + Date::ABBR_DAYNAMES).compact
|
250
|
-
translated.each_with_index { |name, i| date_string.gsub!(name, original[i]) }
|
251
|
-
end
|
252
|
-
end
|
253
253
|
|
254
|
+
end
|
data/app/models/setting.rb
CHANGED
@@ -112,25 +112,13 @@ class Setting < ActiveRecord::Base
|
|
112
112
|
|
113
113
|
|
114
114
|
# Loads settings from YAML files
|
115
|
-
def load_settings_from_yaml
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
# Load default settings, then override with custom settings
|
124
|
-
setting_files.each do |file|
|
125
|
-
if File.exist?(file)
|
126
|
-
begin
|
127
|
-
settings = YAML.load_file(file)
|
128
|
-
# Merge settings into current settings hash (recursively)
|
129
|
-
@@yaml_settings.deep_merge!(settings)
|
130
|
-
rescue Exception => ex
|
131
|
-
puts "Settings couldn't be loaded from #{file}: #{ex.message}"
|
132
|
-
end
|
133
|
-
end
|
115
|
+
def load_settings_from_yaml(file)
|
116
|
+
begin
|
117
|
+
settings = YAML.load_file(file)
|
118
|
+
# Merge settings into current settings hash (recursively)
|
119
|
+
@@yaml_settings.deep_merge!(settings)
|
120
|
+
rescue Exception => ex
|
121
|
+
puts "Settings couldn't be loaded from #{file}: #{ex.message}"
|
134
122
|
end
|
135
123
|
yaml_settings
|
136
124
|
end
|
@@ -138,5 +126,10 @@ class Setting < ActiveRecord::Base
|
|
138
126
|
end
|
139
127
|
|
140
128
|
|
141
|
-
#
|
142
|
-
|
129
|
+
# Load default settings, then override with custom settings, if present.
|
130
|
+
setting_files = [FatFreeCRM.root.join("config", "settings.default.yml")]
|
131
|
+
# Don't override default settings in test environment
|
132
|
+
setting_files << Rails.root.join("config", "settings.yml") unless Rails.env == 'test'
|
133
|
+
setting_files.each do |settings_file|
|
134
|
+
Setting.load_settings_from_yaml(settings_file) if File.exist?(settings_file)
|
135
|
+
end
|