c80_estate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/CODE_OF_CONDUCT.md +49 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +67 -0
  7. data/Rakefile +2 -0
  8. data/app/admin/c80_estate/areas.rb +56 -0
  9. data/app/admin/c80_estate/atypes.rb +44 -0
  10. data/app/admin/c80_estate/prop_names.rb +48 -0
  11. data/app/admin/c80_estate/properties.rb +38 -0
  12. data/app/admin/c80_estate/role_types.rb +40 -0
  13. data/app/admin/c80_estate/uoms.rb +33 -0
  14. data/app/assets/javascript/c80_estate/backend/admin/areas.js +423 -0
  15. data/app/assets/javascript/c80_estate/backend/init.js +36 -0
  16. data/app/assets/javascript/c80_estate/backend/init_selectpicker.js +6 -0
  17. data/app/assets/javascript/c80_estate/lib/jalert.js +16 -0
  18. data/app/assets/javascript/c80_estate_active_admin.js.coffee +4 -0
  19. data/app/assets/stylesheets/c80_estate/backend/admin_areas.scss +109 -0
  20. data/app/assets/stylesheets/c80_estate/backend/admin_users.scss +27 -0
  21. data/app/assets/stylesheets/c80_estate/backend/common.scss +3 -0
  22. data/app/assets/stylesheets/c80_estate/lib/mixins.scss +17 -0
  23. data/app/assets/stylesheets/c80_estate_active_admin.scss +2 -0
  24. data/app/controllers/c80_estate/ajax_controller.rb +17 -0
  25. data/app/models/c80_estate/aphoto.rb +6 -0
  26. data/app/models/c80_estate/area.rb +26 -0
  27. data/app/models/c80_estate/astatus.rb +6 -0
  28. data/app/models/c80_estate/atphoto.rb +6 -0
  29. data/app/models/c80_estate/atype.rb +132 -0
  30. data/app/models/c80_estate/comment.rb +7 -0
  31. data/app/models/c80_estate/item_prop.rb +70 -0
  32. data/app/models/c80_estate/owner.rb +62 -0
  33. data/app/models/c80_estate/pphoto.rb +5 -0
  34. data/app/models/c80_estate/prop_name.rb +19 -0
  35. data/app/models/c80_estate/property.rb +15 -0
  36. data/app/models/c80_estate/role.rb +6 -0
  37. data/app/models/c80_estate/role_type.rb +5 -0
  38. data/app/models/c80_estate/uom.rb +5 -0
  39. data/app/uploaders/c80_estate/aphoto_uploader.rb +21 -0
  40. data/app/uploaders/c80_estate/atphoto_uploader.rb +21 -0
  41. data/app/uploaders/c80_estate/pphoto_uploader.rb +21 -0
  42. data/bin/console +14 -0
  43. data/bin/setup +8 -0
  44. data/c80_estate.gemspec +25 -0
  45. data/config/routes.rb +3 -0
  46. data/db/migrate/20160629033533_create_c80_estate_areas.rb +13 -0
  47. data/db/migrate/20160629033535_create_c80_estate_properties.rb +15 -0
  48. data/db/migrate/20160629034444_create_c80_prop_names.rb +12 -0
  49. data/db/migrate/20160629041414_create_c80_estate_uoms.rb +10 -0
  50. data/db/migrate/20160629090606_create_c80_estate_aphotos.rb +9 -0
  51. data/db/migrate/20160629091313_create_c80_estate_astatuses.rb +9 -0
  52. data/db/migrate/20160629092323_create_c80_item_props.rb +14 -0
  53. data/db/migrate/20160629093030_create_c80_estate_comments.rb +12 -0
  54. data/db/migrate/20160629100505_create_c80_atypes.rb +10 -0
  55. data/db/migrate/20160629205151_create_c80_estate_atphotos.rb +9 -0
  56. data/db/migrate/20160630012727_create_c80_estate_pphotos.rb +9 -0
  57. data/db/migrate/20160630013636_create_join_table_areas_astatuses.rb +12 -0
  58. data/db/migrate/20160630013737_create_join_table_atypes_prop_names.rb +12 -0
  59. data/db/migrate/20160704050000_create_c80_estate_role_types.rb +9 -0
  60. data/db/migrate/20160704063131_create_c80_estate_roles.rb +10 -0
  61. data/db/seeds/50_fill_uoms.rb.example +8 -0
  62. data/db/seeds/55_fill_prop_names.rb.example +51 -0
  63. data/db/seeds/60_fill_atypes.rb.example +29 -0
  64. data/lib/c80_estate.rb +8 -0
  65. data/lib/c80_estate/engine.rb +23 -0
  66. data/lib/c80_estate/version.rb +3 -0
  67. metadata +151 -0
@@ -0,0 +1,36 @@
1
+ // initialize your global object will all your model names
2
+ //YOUR_APP = {
3
+ //
4
+ //};
5
+
6
+ var fLoadingShow = function () {
7
+ $("body").append($('<div id="loading"></div>'));
8
+ };
9
+
10
+ var fLoadingHide = function () {
11
+ $("#loading").remove();
12
+ };
13
+
14
+ //jQuery(document).ready(function ($) {
15
+ // get the page action
16
+ //var action, model, b = $("body");
17
+ //if (b.hasClass("edit")) {
18
+ // action = "edit";
19
+ //} else if (b.hasClass("view")) {
20
+ // action = "view";
21
+ //} else if (b.hasClass("index")) {
22
+ // action = "index"
23
+ //} else if (b.hasClass("new")) {
24
+ // action = "new"
25
+ //}
26
+ //
27
+ //run the code specific to a model and an action
28
+ //for (var m in YOUR_APP) {
29
+ // if (b.hasClass("admin_" + m)) {
30
+ // if (YOUR_APP[m][action] && typeof YOUR_APP[m][action] == "function") {
31
+ // YOUR_APP[m][action]();
32
+ // break;
33
+ // }
34
+ // }
35
+ //}
36
+ //});
@@ -0,0 +1,6 @@
1
+ $(document).ready(function() {
2
+ var $el = $("#admin_user_roles_attributes_0_role_type_id");
3
+ if ($el != null) {
4
+ $el.selectpicker();
5
+ }
6
+ });
@@ -0,0 +1,16 @@
1
+
2
+ var jAlert = function (message) {
3
+ $('<div id="dialog" class="my-dialog" title="Ошибка"><p>'+message+'</p></div>').dialog({
4
+ dialogClass: "no-close",
5
+ modal: true,
6
+ buttons: [
7
+ {
8
+ text: "OK",
9
+ buttonClass: 'nn',
10
+ click: function() {
11
+ $( this ).dialog( "close" );
12
+ }
13
+ }
14
+ ]
15
+ });
16
+ };
@@ -0,0 +1,4 @@
1
+ #= require ./c80_estate/lib/jalert
2
+ #= require ./c80_estate/backend/init
3
+ #= require ./c80_estate/backend/init_selectpicker
4
+ #= require_tree ./c80_estate/backend/admin
@@ -0,0 +1,109 @@
1
+ body.admin_areas {
2
+ &.edit, &.new {
3
+
4
+ select {
5
+ /*padding: 3px 10px 5px 10px;*/
6
+ }
7
+
8
+ input {
9
+ /*font-size: 12px;*/
10
+ }
11
+
12
+ // в этом контейнере живут fieldset-ы, каждый из которых соответствует одному свойству предмета
13
+ li.item_props {
14
+ padding-top: 0;
15
+
16
+ // прячем h3
17
+ h3 {
18
+ display: none;
19
+ }
20
+ // прячем сразу кнопку "Добавить Item prop"
21
+ a.has_many_add {
22
+ display: none;
23
+ }
24
+ // прячем кнопку "убрать свойство"
25
+ a.has_many_remove {
26
+ display: none;
27
+ }
28
+
29
+ // приводим в табличный вид внешний вид
30
+ fieldset {
31
+ margin: 0;
32
+ @include shdw(0.0);
33
+ border: none;
34
+ border-radius: 0;
35
+
36
+ // прячем лейблы
37
+ label {
38
+ display: none;
39
+ }
40
+
41
+ li.select, li.input {
42
+ float: left;
43
+ padding: 3px;
44
+ }
45
+
46
+ select {
47
+ text-align: right;
48
+ float: left;
49
+ &:disabled {
50
+ color: #4C4C4C;
51
+ }
52
+ }
53
+ input {
54
+ float: left;
55
+ width: 400px;
56
+ }
57
+ }
58
+
59
+ }
60
+
61
+ form fieldset > ol > li.boolean {
62
+ height: auto;
63
+ &#item_is_main_input {padding-bottom: 20px;padding-top: 0;}
64
+ &#item_is_sale_input {padding-bottom: 0;}
65
+ label {
66
+ font-weight: bold;
67
+ color: #5E6469;
68
+ }
69
+ }
70
+
71
+ p.inline-hints {
72
+ color: #74b1b2;
73
+ padding-left: 50px;
74
+ }
75
+
76
+ // спрячем артефакт
77
+ li#area_galleries_input {
78
+ fieldset.choices {
79
+ legend.label { display:none; }
80
+ }
81
+ }
82
+
83
+ li.has_many_container {
84
+ width: 80%;
85
+ float: right;
86
+ padding: 0;
87
+
88
+ &.aphotos {
89
+ fieldset.has_many_fields {
90
+ background-color: transparent;
91
+ box-shadow: none;
92
+ border: 1px solid #dddddd;
93
+ }
94
+ h3 {
95
+ display: none;
96
+ }
97
+
98
+ }
99
+
100
+ }
101
+
102
+ .fieldset_item_props {
103
+ background-color: white !important;
104
+ box-shadow: none !important;
105
+ legend { display: none !important; }
106
+ }
107
+
108
+ }
109
+ }
@@ -0,0 +1,27 @@
1
+ body.admin_admin_users {
2
+ &.edit, &.new {
3
+
4
+ li.has_many_container {
5
+
6
+ &.roles {
7
+
8
+ fieldset.has_many_fields {
9
+ background-color: transparent;
10
+ box-shadow: none;
11
+ border: none;
12
+
13
+ }
14
+
15
+ h3 {
16
+ display: none;
17
+ }
18
+ }
19
+
20
+ }
21
+
22
+ a.has_many_add {
23
+ display: none;
24
+ }
25
+
26
+ }
27
+ }
@@ -0,0 +1,3 @@
1
+ #admin_user_1 {
2
+ display: none;
3
+ }
@@ -0,0 +1,17 @@
1
+ @mixin shdw($val) {
2
+ -webkit-box-shadow: 0 0 7px 0 rgba(0, 0, 0, $val);
3
+ -moz-box-shadow: 0 0 7px 0 rgba(0, 0, 0, $val);
4
+ box-shadow: 0 0 7px 0 rgba(0, 0, 0, $val);
5
+ /* For IE 8 */
6
+ -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=$val, Direction=135, Color='#000000')";
7
+ /* For IE 5.5 - 7 */
8
+ filter: progid:DXImageTransform.Microsoft.Shadow(Strength=$val, Direction=135, Color='#000000');
9
+ }
10
+
11
+ @mixin opacity($val) {
12
+ -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$val)";
13
+ filter: alpha(opacity=$val);
14
+ -moz-opacity:$val;
15
+ -khtml-opacity: $val;
16
+ opacity: $val;
17
+ }
@@ -0,0 +1,2 @@
1
+ @import "c80_estate/lib/**/*";
2
+ @import "c80_estate/backend/**/*";
@@ -0,0 +1,17 @@
1
+ module C80Estate
2
+ class AjaxController < ActionController::Base
3
+
4
+ def get_atype_propnames
5
+
6
+ atype_id = request.params[:atype_id]
7
+ obj = Atype.get_propnames(atype_id)
8
+
9
+ respond_to do |format|
10
+ format.js { render json: obj, status: :ok }
11
+ # format.json
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ module C80Estate
2
+ class Aphoto < ActiveRecord::Base
3
+ belongs_to :area
4
+ mount_uploader :image, AphotoUploader
5
+ end
6
+ end
@@ -0,0 +1,26 @@
1
+ module C80Estate
2
+ class Area < ActiveRecord::Base
3
+ belongs_to :property
4
+ belongs_to :atype
5
+ belongs_to :owner, :polymorphic => true
6
+ has_many :item_props, :dependent => :destroy
7
+ accepts_nested_attributes_for :item_props,
8
+ :reject_if => lambda { |attributes|
9
+ # puts "attributes:: #{attributes}"
10
+ # attributes:: {"value"=>"", "prop_name_id"=>""}
11
+ !attributes.present? || \
12
+ !attributes[:value].present? || \
13
+ !attributes[:prop_name_id].present?
14
+ },
15
+ :allow_destroy => true
16
+ has_many :aphotos, :dependent => :destroy # одна или несколько фоток
17
+ accepts_nested_attributes_for :aphotos,
18
+ :reject_if => lambda { |attributes|
19
+ !attributes.present?
20
+ },
21
+ :allow_destroy => true
22
+ has_many :comments, :dependent => :destroy # площадь можно прокомментировать
23
+ has_and_belongs_to_many :astatuses, # единственный статус: либо занята, либо свободна
24
+ :join_table => 'c80_estate_areas_astatuses'
25
+ end
26
+ end
@@ -0,0 +1,6 @@
1
+ module C80Estate
2
+ class Astatus < ActiveRecord::Base
3
+ has_and_belongs_to_many :areas, # Площадь имеет единственный статус: либо занята, либо свободна
4
+ :join_table => 'c80_estate_areas_astatuses'
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module C80Estate
2
+ class Atphoto < ActiveRecord::Base
3
+ belongs_to :atype
4
+ mount_uploader :image, AtphotoUploader
5
+ end
6
+ end
@@ -0,0 +1,132 @@
1
+ require "babosa"
2
+
3
+ module C80Estate
4
+
5
+ class Atype < ActiveRecord::Base
6
+
7
+ # http://stackoverflow.com/questions/9382708/rails-3-has-many-changed
8
+ has_and_belongs_to_many :prop_names,
9
+ :join_table => 'c80_estate_atypes_prop_names',
10
+ :after_add => :after_add_prop_names,
11
+ :after_remove => :after_remove_prop_names
12
+
13
+ has_many :areas, :dependent => :destroy
14
+ has_many :properties, :dependent => :destroy
15
+ has_many :atphotos, :dependent => :destroy # одна или несколько фоток
16
+
17
+ extend FriendlyId
18
+ friendly_id :slug_candidates, :use => :slugged
19
+
20
+ def slug_candidates
21
+ [:title] + Array.new(6) {|index| [:title, index+2]}
22
+ end
23
+
24
+ def normalize_friendly_id(input)
25
+ input.to_s.to_slug.normalize(transliterations: :russian).to_s
26
+ end
27
+
28
+ # • этот метод дёргает только StrsubcatSweeper
29
+ # • после вызова метода - значение сбрасывается в false
30
+ def prop_names_changed?
31
+ res = @mark_prop_names_changed
32
+ @mark_prop_names_changed = false
33
+ res
34
+ end
35
+
36
+ def get_list_removed_props
37
+ @list_removed_props = [] unless @list_removed_props.present?
38
+ res = @list_removed_props
39
+ @list_removed_props = []
40
+ res
41
+ end
42
+
43
+ # выдать все характеристики, присущие данной категории, вместе с единицами измерений
44
+ def self.get_propnames(atype_id)
45
+
46
+ =begin
47
+ >> stdh_get_atype_propnames(1)
48
+ <stdh_get_atype_propnames> BEGIN
49
+ (0.2ms)
50
+ SELECT
51
+ `prop_names`.`id`,
52
+ `prop_names`.`title`,
53
+ `prop_names`.`is_excluded_from_filtering`,
54
+ `uoms`.`title` as uom_title
55
+ FROM `prop_names`
56
+ INNER JOIN `prop_names_atypes` ON `prop_names`.`id` = `prop_names_atypes`.`prop_name_id`
57
+ LEFT OUTER JOIN uoms ON uoms.id = prop_names.uom_id
58
+ WHERE `prop_names_atypes`.`atype_id` = 1;
59
+
60
+ {"id"=>18, "title"=>"Цена за шт.", "is_excluded_from_filtering"=>1, "uom_title"=>"руб"}
61
+ {"id"=>19, "title"=>"Цена за шт. (старая)", "is_excluded_from_filtering"=>1, "uom_title"=>"руб"}
62
+ {"id"=>20, "title"=>"Цена за м²", "is_excluded_from_filtering"=>1, "uom_title"=>"руб"}
63
+ {"id"=>21, "title"=>"Цена за м² (старая)", "is_excluded_from_filtering"=>1, "uom_title"=>"руб"}
64
+ {"id"=>23, "title"=>"Размер", "is_excluded_from_filtering"=>0, "uom_title"=>nil}
65
+ {"id"=>24, "title"=>"Страна", "is_excluded_from_filtering"=>0, "uom_title"=>nil}
66
+ {"id"=>25, "title"=>"Прочность на сжатие", "is_excluded_from_filtering"=>0, "uom_title"=>"кгс/см²"}
67
+ {"id"=>26, "title"=>"Коэффициент теплопроводности", "is_excluded_from_filtering"=>0, "uom_title"=>"Вт/м×°C"}
68
+ {"id"=>27, "title"=>"Марка по морозостойкости", "is_excluded_from_filtering"=>0, "uom_title"=>nil}
69
+ {"id"=>28, "title"=>"Водопоглощение", "is_excluded_from_filtering"=>0, "uom_title"=>"%"}
70
+ {"id"=>29, "title"=>"Цвет", "is_excluded_from_filtering"=>0, "uom_title"=>nil}
71
+ {"id"=>30, "title"=>"Пустотность", "is_excluded_from_filtering"=>0, "uom_title"=>nil}
72
+ {"id"=>31, "title"=>"Формовка", "is_excluded_from_filtering"=>0, "uom_title"=>nil}
73
+ {"id"=>32, "title"=>"Поверхность", "is_excluded_from_filtering"=>0, "uom_title"=>nil}
74
+ {"id"=>33, "title"=>"Вес", "is_excluded_from_filtering"=>0, "uom_title"=>nil}
75
+ {"id"=>34, "title"=>"Количество на поддоне", "is_excluded_from_filtering"=>1, "uom_title"=>"шт"}
76
+ {"id"=>35, "title"=>"Тип кирпича", "is_excluded_from_filtering"=>0, "uom_title"=>nil}
77
+ {"id"=>36, "title"=>"Производитель", "is_excluded_from_filtering"=>0, "uom_title"=>nil}
78
+ {"id"=>37, "title"=>"Артикул", "is_excluded_from_filtering"=>1, "uom_title"=>nil}
79
+ {"id"=>38, "title"=>"Формат", "is_excluded_from_filtering"=>0, "uom_title"=>nil}
80
+ <stdh_get_atype_propnames> END
81
+ =end
82
+
83
+ Rails.logger.debug "<Atype.get_propnames> BEGIN"
84
+ sql = "
85
+ SELECT
86
+ `c80_estate_prop_names`.`id`,
87
+ `c80_estate_prop_names`.`title`,
88
+ `c80_estate_prop_names`.`is_excluded_from_filtering`,
89
+ `c80_estate_uoms`.`title` as uom_title
90
+ FROM `c80_estate_prop_names`
91
+ INNER JOIN `c80_estate_atypes_prop_names` ON `c80_estate_prop_names`.`id` = `c80_estate_atypes_prop_names`.`prop_name_id`
92
+ LEFT OUTER JOIN `c80_estate_uoms` ON `c80_estate_uoms`.`id` = `c80_estate_prop_names`.`uom_id`
93
+ WHERE `c80_estate_atypes_prop_names`.`atype_id` = #{atype_id};
94
+ "
95
+
96
+ result = []
97
+ rows = ActiveRecord::Base.connection.execute(sql)
98
+ rows.each(:as => :hash) do |row|
99
+ result << row
100
+ end
101
+
102
+ Rails.logger.debug "<Atype.get_propnames> END"
103
+ result
104
+
105
+ end
106
+
107
+ private
108
+
109
+ # • Два метода after_add_prop_names и after_remove_prop_names
110
+ # слушают изменения prop_names, и, при их наличии,
111
+ # выставляют флаг mark_prop_names_changed в true.
112
+ # • Этот флаг вертает обратно в false
113
+ # метод after_update "чистильщика" StrsubcatSweeper.
114
+
115
+ def after_add_prop_names(prop_name)
116
+ unless new_record?
117
+ puts "<Strsubcat.after_add_prop_names>: #{prop_name.title}"
118
+ @mark_prop_names_changed = true
119
+ end
120
+ end
121
+
122
+ def after_remove_prop_names(prop_name)
123
+ puts "<Strsubcat.after_remove_prop_names>: #{prop_name.title}"
124
+ @mark_prop_names_changed = true
125
+ @list_removed_props = [] unless @list_removed_props.present?
126
+ @list_removed_props << prop_name.id
127
+ end
128
+
129
+ end
130
+
131
+
132
+ end
@@ -0,0 +1,7 @@
1
+ module C80Estate
2
+ class Comment < ActiveRecord::Base
3
+ belongs_to :area
4
+ belongs_to :property
5
+ belongs_to :owner, :polymorphic => true
6
+ end
7
+ end