c80_estate 0.1.0.2 → 0.1.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7b85f1023982f4ed95d538e615554d1ec417f55a
4
- data.tar.gz: 8db2342ce5cafa27e6b9a556b288871a234b4a03
3
+ metadata.gz: 347ae43df7eb3ed899e9ae21f3a85648fff17baa
4
+ data.tar.gz: 38e409296f4dd3fb71867a38918da9c68823b678
5
5
  SHA512:
6
- metadata.gz: f1170fe161cf6f23c09cd2b33bb370fff2086a929e4fc6e1f27004c75ef991c42753288551eee782c62b07e762b10c902e1ac20d9ac5cf19486f1f62520f001b
7
- data.tar.gz: 90132ddd947b2912e9a3095270270e3f264937920c12618659f4be22101c82a438de10551015461d87699d8db93dfef81b95b2099281f5b1a94324f298fa4442
6
+ metadata.gz: 858bcd250a2e8c33bbd56e5b28aa8c3849e9843392868a3433b53498cd3574dd7d5faccbd014f917816f6a918fc951e3533b02d0bebcaa4dc93c2fdacae44a22
7
+ data.tar.gz: 01a4d0cf2c9c6edf973f25c782ecbd1d09405592e206d8ee5dff257c86b22a010332947f266f1119c3d391ab211785bac73671530ebbec93a63c67ae19225ef3
@@ -0,0 +1,37 @@
1
+ ActiveAdmin.register C80Estate::Pstat, as: 'Pstat' do
2
+
3
+ # scope_to :current_admin_user, association_method: :sites_list
4
+
5
+ menu :label => "Объекты", :parent => 'Статистика'
6
+
7
+ config.sort_order = 'id_asc'
8
+
9
+ filter :property_id,
10
+ :as => :select,
11
+ :collection => -> { C80Estate::Property.all.map { |p| ["#{p.title}", p.id] } },
12
+ :input_html => {:class => 'selectpicker', 'data-size' => "10", 'data-width' => '100%'}
13
+
14
+ filter :atype_id,
15
+ :as => :select,
16
+ :collection => -> { C80Estate::Atype.all.map { |p| ["#{p.title}", p.id] } },
17
+ :input_html => {:class => 'selectpicker', 'data-size' => "10", 'data-width' => '100%'}
18
+
19
+ filter :created_at
20
+
21
+ index do
22
+ selectable_column
23
+ column :property do |ptype|
24
+ ptype.property_title
25
+ end
26
+ column :atype do |ptype|
27
+ ptype.atype_title
28
+ end
29
+ column :free_areas
30
+ column :busy_areas
31
+ column :coef_busy
32
+ column :coef_busy_sq
33
+ column :created_at
34
+ actions
35
+ end
36
+
37
+ end
@@ -19,7 +19,9 @@ ActiveAdmin.register C80Estate::Sevent, as: 'Sevent' do
19
19
  # :input_html => {:class => 'selectpicker', 'data-size' => "10", 'data-width' => '100%'}
20
20
  filter :area_id,
21
21
  :as => :select,
22
- :collection => -> { C80Estate::Area.all.map { |p| ["#{p.title}", p.id] } },
22
+ :collection => -> { C80Estate::Area.all.map { |a|
23
+ ["#{a.property.title}: #{a.title}", a.id]
24
+ } },
23
25
  :input_html => {:class => 'selectpicker', 'data-size' => "10", 'data-width' => '100%'}
24
26
  # filter :atype_id,
25
27
  # :as => :select,
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+
3
+ var fPstatsIndex = function () {
4
+
5
+ // элементы html страницы
6
+ var $main_content; // правая сторона, там живёт таблица
7
+ var $select_atype; // фильтр atype
8
+ var $select_property; // фильтр property
9
+ var $input_start_date; // фильтр "дата начала периода"
10
+ var $input_end_date; // фильтр "дата конца периода"
11
+ var $h2_page_title; // заголовок страницы
12
+
13
+ // компонент "над таблицей"
14
+ var $div_index_adds;
15
+ var $div_busy_coef;
16
+ var $p_busy_coef; // здесь выводим число - коэф-т эффективности
17
+ var $p_ecoef_mess; // здесь вешаем hint на подпись "эффективность"
18
+ var $p_ecoef_comment; // здесь выводим комментарий
19
+ var $div_area_text_stats;
20
+ var $ul_props; // здесь выводим текстовые свойства
21
+ var $div_graph; // в этом div живет график
22
+ var $div_graph2; // в этом div живет график
23
+
24
+ var fBuild = function () {
25
+
26
+ // зафиксируем html элементы
27
+ $main_content = $('#main_content');
28
+ $select_atype = $("#q_atype_id");
29
+ $select_property = $("#q_property_id");
30
+ $input_start_date = $("#q_created_at_gteq");
31
+ $input_end_date = $("#q_created_at_lteq");
32
+ $h2_page_title = $("h2#page_title");
33
+
34
+ // построим компонент "над таблицей"
35
+ $div_index_adds = $("<div id='index_adds'></div>");
36
+
37
+ $div_busy_coef = $("<div id='coef'></div>");
38
+ $p_busy_coef = $("<p class='val'></p>");
39
+ $p_ecoef_mess = $("<p class='title'><abbr class='abbr_ecoef' title='TITLE'>Занятость</abbr></p>");
40
+ $p_ecoef_comment = $("<p class='comment'></p>");
41
+
42
+ $div_busy_coef.append($p_busy_coef);
43
+ $div_busy_coef.append($p_ecoef_mess);
44
+ $div_busy_coef.append($p_ecoef_comment);
45
+
46
+ $div_area_text_stats = $("<div id='text_stats'></div>");
47
+ $ul_props = $("<ul><li id='title'></li><li id='born_date'></li><li id='atype_filter'></li><li id='all_areas_count'></li><li id='free_areas_count'></li><li id='busy_areas_count'></li></ul>");
48
+ $div_area_text_stats.append($ul_props);
49
+
50
+ $div_graph = $("<div id='graph'></div>");
51
+ $div_graph2 = $("<div id='graph2'></div>");
52
+
53
+ $div_index_adds.append($div_busy_coef);
54
+ $div_index_adds.append($div_area_text_stats);
55
+ $div_index_adds.append($div_graph);
56
+ $div_index_adds.append($div_graph2);
57
+
58
+ $main_content.prepend($div_index_adds);
59
+
60
+ // теперь покажем
61
+ $main_content.css('opacity', '1.0');
62
+ };
63
+
64
+ var fRequest = function () {
65
+
66
+ var atype_id = $select_atype.val();
67
+ var property_id = $select_property.val();
68
+ var start_date = $input_start_date.val();
69
+ var end_date = $input_end_date.val();
70
+
71
+ $.ajax({
72
+ url: '/estate/properties_busy_coef',
73
+ type: 'POST',
74
+ dataType: 'json',
75
+ data: {
76
+ atype_id: atype_id,
77
+ prop_id: property_id,
78
+ start_date: start_date,
79
+ end_date: end_date
80
+ }
81
+ }).done(function (data, result) {
82
+ if (result == 'success') {
83
+ console.log(data);
84
+
85
+ $p_busy_coef.text(data["busy_coef"]);
86
+ $p_ecoef_comment.html(data["comment"]);
87
+ $p_ecoef_mess.find('.abbr_ecoef').attr('title', data["abbr"]);
88
+
89
+ if (data["props"] != undefined) {
90
+
91
+ var i, iob, itag, ival, $ili;
92
+ for (i = 0; i < data["props"].length; i++) {
93
+ iob = data["props"][i];
94
+ itag = iob["tag"];
95
+ ival = iob["val"];
96
+ $ili = $ul_props.find("#" + itag);
97
+ $ili.html(ival);
98
+ }
99
+
100
+ }
101
+
102
+ if (data["graph"] != undefined) {
103
+ fDrawChart(data["graph"], data["graph_dynamic"]);
104
+ }
105
+
106
+ $h2_page_title.text(data["title"]);
107
+ $h2_page_title.css('opacity', '1.0');
108
+ $(document).attr('title', data["title"]);
109
+
110
+ } else {
111
+ alert('fail: /estate/properties_busy_coef');
112
+ }
113
+ //fPreloaderHide();
114
+ });
115
+
116
+ //fPreloaderShow();
117
+ };
118
+
119
+ var fInit = function () {
120
+ fBuild();
121
+ fRequest();
122
+ };
123
+
124
+ var fDrawChart = function (data_array_rows_radial, data_array_rows_dynamic) {
125
+
126
+ google.charts.load('current', {'packages': ['corechart']});
127
+ google.charts.setOnLoadCallback(drawChart);
128
+
129
+ function drawChart() {
130
+
131
+ var data, options, chart;
132
+
133
+ if (data_array_rows_radial != undefined) {
134
+ data = google.visualization.arrayToDataTable(data_array_rows_radial);
135
+
136
+ options = {
137
+ title: ''
138
+ };
139
+
140
+ chart = new google.visualization.PieChart(document.getElementById('graph'));
141
+
142
+ chart.draw(data, options);
143
+ }
144
+
145
+ if (data_array_rows_dynamic != undefined) {
146
+ //data_array = [
147
+ // ['Director (Year)', 'Rotten Tomatoes', 'IMDB'],
148
+ // ['Alfred Hitchcock (1935)', 8.4, 7.9],
149
+ // ['Ralph Thomas (1959)', 6.9, 6.5],
150
+ // ['Don Sharp (1978)', 6.5, 6.4],
151
+ // ['James Hawes (2008)', 4.4, 6.2]
152
+ //]
153
+
154
+ //var data = google.visualization.arrayToDataTable(data_array_rows_dynamic);
155
+
156
+ data = new google.visualization.DataTable();
157
+ data.addColumn('date', ''); // Implicit domain column.
158
+ data.addColumn('number', ''); // Implicit data column.
159
+ //data.addColumn({type:'number', role:'interval'});
160
+ //data.addColumn({type:'number', role:'interval'});
161
+ //data.addColumn('number', 'Expenses');
162
+
163
+ var i, iob, yearValue, monthValue, dayValue;
164
+ for (i = 0; i < data_array_rows_dynamic.length; i++) {
165
+ iob = data_array_rows_dynamic[i];
166
+ yearValue = iob[0].substr(0, 4);
167
+ monthValue = iob[0].substr(5, 2) - 1;
168
+ dayValue = iob[0].substr(8, 2);
169
+ console.log(iob + " => " + yearValue + "/" + monthValue + "/" + dayValue); // + ": " + data_array_rows_dynamic[i][0]
170
+ data_array_rows_dynamic[i][0] = new Date(parseInt(yearValue), parseInt(monthValue), parseInt(dayValue));
171
+ }
172
+
173
+ data.addRows(data_array_rows_dynamic);
174
+
175
+ options = {
176
+ title: 'Занятость',
177
+ vAxis: {title: '', ticks: [0, 1]},
178
+ ignoreBounds: true,
179
+ isStacked: false
180
+ };
181
+
182
+ chart = new google.visualization.SteppedAreaChart(document.getElementById('graph2'));
183
+
184
+ chart.draw(data, options);
185
+ }
186
+
187
+ }
188
+
189
+ if (data_array_rows_radial != undefined) {
190
+ $('#graph').css('opacity', '1.0').css('display', 'block');
191
+ }
192
+
193
+ if (data_array_rows_dynamic != undefined) {
194
+ $('#graph2').css('opacity', '1.0').css('display', 'block');
195
+ }
196
+
197
+ };
198
+
199
+ fInit();
200
+
201
+ };
202
+
203
+ var fPstatsEdit = function () {
204
+
205
+ alert("edit");
206
+
207
+ };
208
+
209
+ var fPstatsNew = function () {
210
+
211
+ alert("new");
212
+
213
+ };
214
+
215
+ YOUR_APP.pstats = {
216
+ edit: fPstatsEdit,
217
+ "new": fPstatsNew,
218
+ index: fPstatsIndex
219
+ };
@@ -0,0 +1,131 @@
1
+ body.admin_pstats {
2
+
3
+ &.index {
4
+
5
+ div#main_content {
6
+ opacity: 0;
7
+
8
+ -webkit-transition: opacity .2s ease-in;
9
+ -moz-transition: opacity .2s ease-in;
10
+ -ms-transition: opacity .2s ease-in;
11
+ -o-transition: opacity .2s ease-in;
12
+ transition: opacity .2s ease-in;
13
+
14
+ div#index_adds {
15
+ height: calc(183px + 15px);
16
+ min-height: calc(183px + 15px);
17
+ margin-bottom: 0;
18
+
19
+ > div {
20
+ float: left;
21
+ padding: 10px;
22
+ border-radius: 2px;
23
+ border: 2px solid #f1f1f1;
24
+ height: 183px;
25
+
26
+ &#coef {
27
+ width: 200px;
28
+ text-align: center;
29
+
30
+ p {
31
+ width: 100%;
32
+
33
+ &.val {
34
+ margin-top: 15px;
35
+ margin-bottom: 0;
36
+ font-size: 40px;
37
+ }
38
+
39
+ }
40
+ }
41
+
42
+ &#text_stats {
43
+ width: 400px;
44
+ margin-left: 30px;
45
+
46
+ ul {
47
+ padding: 0 5px;
48
+ list-style: none;
49
+ #title {
50
+ font-weight: bold;
51
+ }
52
+ }
53
+
54
+ }
55
+
56
+ &#graph {
57
+ width: calc(100% - 200px - 400px - 30px - 30px);
58
+ /*width: 100%;*/
59
+ /*height: 200px;*/
60
+ /*margin-top: 15px;*/
61
+
62
+ margin-left: 30px;
63
+ padding: 0;
64
+ display: none;
65
+ opacity: 0;
66
+
67
+ -webkit-transition: opacity .2s ease-in;
68
+ -moz-transition: opacity .2s ease-in;
69
+ -ms-transition: opacity .2s ease-in;
70
+ -o-transition: opacity .2s ease-in;
71
+ transition: opacity .2s ease-in;
72
+ }
73
+
74
+ &#graph2 {
75
+ width: 100%;
76
+ margin-top: 15px;
77
+ padding: 0;
78
+ display: none;
79
+ opacity: 0;
80
+
81
+ -webkit-transition: opacity .2s ease-in;
82
+ -moz-transition: opacity .2s ease-in;
83
+ -ms-transition: opacity .2s ease-in;
84
+ -o-transition: opacity .2s ease-in;
85
+ transition: opacity .2s ease-in;
86
+
87
+ }
88
+
89
+ }
90
+ }
91
+
92
+ }
93
+
94
+ .batch_actions_selector {
95
+ display: none;
96
+ }
97
+
98
+ .action_items {
99
+ display: none;
100
+ }
101
+
102
+ a.delete_link {
103
+ display: none;
104
+ }
105
+
106
+ .col-actions {
107
+ text-align: right;
108
+ width: 99px !important;
109
+ }
110
+
111
+ a.edit_link {
112
+ display: none;
113
+ }
114
+
115
+ h2#page_title {
116
+ opacity: 0;
117
+
118
+ -webkit-transition: opacity .2s ease-in;
119
+ -moz-transition: opacity .2s ease-in;
120
+ -ms-transition: opacity .2s ease-in;
121
+ -o-transition: opacity .2s ease-in;
122
+ transition: opacity .2s ease-in;
123
+ }
124
+
125
+ div.blank_slate_container {
126
+ display: none !important;
127
+ }
128
+
129
+ }
130
+
131
+ }
@@ -106,6 +106,10 @@ body.admin_sevents {
106
106
  transition: opacity .2s ease-in;
107
107
  }
108
108
 
109
+ div.blank_slate_container {
110
+ display: none !important;
111
+ }
112
+
109
113
  }
110
114
 
111
115
  }
@@ -16,16 +16,41 @@ module C80Estate
16
16
  def areas_ecoef
17
17
 
18
18
  area_id = request.params[:area_id] == "" ? nil:request.params[:area_id]
19
+ atype_id = request.params[:atype_id] == "" ? nil:request.params[:atype_id]
19
20
  start_date = request.params[:start_date] == "" ? nil:request.params[:start_date]
20
21
  end_date = request.params[:end_date] == "" ? nil:request.params[:end_date]
21
22
 
22
- obj = Sevent.ecoef(area_id: area_id, start_date: start_date, end_date: end_date)
23
+ obj = Sevent.ecoef(area_id: area_id,
24
+ start_date: start_date,
25
+ end_date: end_date,
26
+ atype_id: atype_id
27
+ )
23
28
 
24
29
  respond_to do |format|
25
30
  format.js { render json: obj, status: :ok }
26
31
  # format.json
27
32
  end
28
33
  end
34
+
35
+ def properties_busy_coef
36
+
37
+ prop_id = request.params[:prop_id] == "" ? nil:request.params[:prop_id]
38
+ start_date = request.params[:start_date] == "" ? nil:request.params[:start_date]
39
+ atype_id = request.params[:atype_id] == "" ? nil:request.params[:atype_id]
40
+ end_date = request.params[:end_date] == "" ? nil:request.params[:end_date]
41
+
42
+ obj = Pstat.busy_coef(prop_id: prop_id,
43
+ start_date: start_date,
44
+ end_date: end_date,
45
+ atype_id: atype_id
46
+ )
47
+
48
+ respond_to do |format|
49
+ format.js { render json: obj, status: :ok }
50
+ # format.json
51
+ end
52
+
53
+ end
29
54
 
30
55
  end
31
56
  end
@@ -37,10 +37,20 @@ module C80Estate
37
37
  self.joins(:astatuses).where(:c80_estate_astatuses => { tag: 'free'})
38
38
  end
39
39
 
40
+ # посчитает кол-во свободных метров
41
+ def self.free_areas_sq
42
+ 1
43
+ end
44
+
40
45
  def self.busy_areas
41
46
  self.joins(:astatuses).where(:c80_estate_astatuses => { tag: 'busy'})
42
47
  end
43
48
 
49
+ # посчитает кол-во занятых метров
50
+ def self.busy_areas_sq
51
+ 1
52
+ end
53
+
44
54
  def atype_title
45
55
  res = "-"
46
56
  if atype.present?
@@ -93,37 +103,95 @@ module C80Estate
93
103
 
94
104
  # при создании площади генерится начальное событие
95
105
  def create_initial_sevent
96
- Rails.logger.debug "<Area.create_initial_sevent>"
106
+ Rails.logger.debug "<Area.create_initial_sevent> self.astatuses.count = #{self.astatuses.count}"
107
+
108
+ # [**]
109
+ if self.astatuses.count > 0
110
+ Rails.logger.debug "<Area.create_initial_sevent> aga: self.astatuses.first.title = #{self.astatuses.first.title}"
111
+
112
+ s = Sevent.create!({
113
+ area_id: self.id,
114
+ atype_id: self.atype_id,
115
+ property_id: self.property_id,
116
+ astatus_id: self.astatus_id,
117
+ auser_id: self.owner_id, # инициатор события - создатель Площади
118
+ auser_type: 'AdminUser',
119
+ created_at: self.created_at
120
+ })
97
121
 
98
- Sevent.create!({
99
- area_id: self.id,
100
- atype_id: self.atype_id,
101
- property_id: self.property_id,
102
- astatus_id: self.astatus_id,
103
- auser_id: self.owner_id, # инициатор события - создатель Площади
104
- auser_type: 'AdminUser'
105
- })
122
+ # см [*]
123
+ # if last_known_sevent == ''
124
+ # pparams[:created_at] = self.created_at
125
+ # end
126
+ #
127
+ # pparams = {
128
+ # atype_id: nil,
129
+ # property_id: self.property_id,
130
+ # sevent_id: s.id
131
+ # }
132
+
133
+ # генерим запись с общими данными
134
+ # связываем её с Sevent
135
+ # чтобы можно было удалить как dependent => destroy
136
+ # Pstat.create!(pparams)
137
+
138
+ end
106
139
 
107
140
  end
108
141
 
109
142
  def check_and_generate_sevent
110
- Rails.logger.debug "<Area.check_and_generate_sevent>"
111
143
 
112
144
  # находим последнее известное событие
113
145
  # фиксируем его статус
114
- last_known_sevent = self.sevents.last.astatus.tag
146
+ last_known_sevent = ""
147
+ if self.sevents.count > 0
148
+ last_known_sevent = self.sevents.last.astatus.tag
149
+ end
115
150
 
116
151
  # если статус этого события отличен
117
- # от нового статуса - генерим событие
152
+ # от нового статуса - генерим события
153
+ Rails.logger.debug "<Area.check_and_generate_sevent> last_known_sevent = #{last_known_sevent}, self.astatuses.first.tag = #{self.astatuses.first.tag}"
154
+
118
155
  if last_known_sevent != self.astatuses.first.tag
119
- Sevent.create!({
120
- area_id: self.id,
121
- atype_id: self.atype_id,
122
- property_id: self.property_id,
123
- astatus_id: self.astatus_id,
124
- auser_id: self.owner_id, # инициатор события - редактор Площади
125
- auser_type: 'AdminUser'
126
- })
156
+ Rails.logger.debug "<Area.check_and_generate_sevent> aga"
157
+ sparams = {
158
+ area_id: self.id,
159
+ atype_id: self.atype_id,
160
+ property_id: self.property_id,
161
+ astatus_id: self.astatus_id,
162
+ auser_id: self.owner_id, # инициатор события - редактор Площади
163
+ auser_type: 'AdminUser'
164
+ }
165
+
166
+ # если неизвестен статус последнего события,
167
+ # значит событий изменения статуса площади ещё не было
168
+ # значит нужно создать первое событие и дату его создания
169
+ # приравнять дате создания площади [*]
170
+ # такая штука случается, когда заполняем данными из seed файла,
171
+ # и при создании не получилось фишка с передачей :astatus_ids => [1] в create!({..})
172
+ # по-этому и появился этот код. Также по теме код из [**]
173
+ if last_known_sevent == ''
174
+ sparams[:created_at] = self.created_at
175
+ end
176
+
177
+ s = Sevent.create!(sparams)
178
+
179
+ pparams = {
180
+ atype_id: nil,
181
+ property_id: self.property_id,
182
+ sevent_id: s.id
183
+ }
184
+
185
+ # см [*]
186
+ if last_known_sevent == ''
187
+ pparams[:created_at] = self.created_at
188
+ end
189
+
190
+ # генерим запись с общими данными
191
+ # связываем её с Sevent
192
+ # чтобы можно было удалить как dependent => destroy
193
+ Pstat.create!(pparams)
194
+
127
195
  end
128
196
 
129
197
  end
@@ -16,6 +16,8 @@ module C80Estate
16
16
 
17
17
  has_many :sevents, :dependent => :nullify
18
18
 
19
+ has_many :pstats, :dependent => :nullify
20
+
19
21
  extend FriendlyId
20
22
  friendly_id :slug_candidates, :use => :slugged
21
23
 
@@ -13,6 +13,7 @@ module C80Estate
13
13
  has_many :areas, :dependent => :destroy
14
14
  has_many :comments, :dependent => :destroy
15
15
  has_many :sevents, :dependent => :destroy
16
+ has_many :pstats, :dependent => :destroy
16
17
 
17
18
  def assigned_person_title
18
19
  res = "-"
@@ -0,0 +1,289 @@
1
+ module C80Estate
2
+ class Pstat < ActiveRecord::Base
3
+
4
+ belongs_to :property
5
+ belongs_to :atype
6
+ belongs_to :sevent
7
+
8
+ # nil, если это запись с общими данными, а не astatus related запись
9
+ # (добавлена только для того, чтобы можно было :dependend => :destroy)
10
+ belongs_to :parent, :class_name => 'C80Estate::Pstat'
11
+ has_many :pstats, :foreign_key => 'parent_id', :dependent => :destroy
12
+
13
+ # рассчитаем коэф-ты занятости
14
+ before_create :calc_busy_coefs
15
+
16
+ # сгенерим atype related записи
17
+ after_create :generate_atype_pstats
18
+
19
+ def self.busy_coef(prop_id: nil, atype_id: nil, start_date: nil, end_date: nil)
20
+ # start_date: строка вида 2015-12-12
21
+
22
+ result = {}
23
+
24
+ # если ничего не подано - просто выберем все занятые площади и поделим на все известные площади
25
+ if prop_id.nil? && atype_id.nil? && start_date.nil? && end_date.nil?
26
+
27
+ all_areas_count = Area.all.count
28
+ free_areas_count = Area.free_areas.count
29
+ busy_areas_count = Area.busy_areas.count
30
+
31
+ ddd = '-'
32
+ if self.count > 0
33
+ ddd = Time.at(self.first.created_at).strftime('%Y/%m/%d')
34
+ end
35
+
36
+ result[:busy_coef] = sprintf "%.2f%", busy_areas_count*1.0/all_areas_count*100.0
37
+ result[:comment] = "<abbr title='Период рассчёта занятости: с момента самого первого известного события до текущего дня'>C #{ddd} по #{Time.now.year}/#{sprintf "%02d", Time.now.month}/#{sprintf "%02d", Time.now.day}</abbr>"
38
+ result[:abbr] = 'Показана занятость для всех площадей всех объектов недвижимости за весь период'
39
+ result[:title] = 'Статистика - Все объекты недвижимости'
40
+ result[:props] = [
41
+ {tag: 'all_areas_count', val: "Площадей всего: #{all_areas_count}"},
42
+ {tag: 'free_areas_count', val: "Площадей свободно: #{free_areas_count}"},
43
+ {tag: 'busy_areas_count', val: "Площадей занято: #{busy_areas_count}"}
44
+ ]
45
+
46
+ Rails.logger.debug "<Pstat.busy_coef> busy_areas_count = #{ busy_areas_count }"
47
+ Rails.logger.debug "<Pstat.busy_coef> all_areas_count = #{ all_areas_count }"
48
+ Rails.logger.debug "<Pstat.busy_coef> result[:busy_coef] = #{ result[:busy_coef] }"
49
+
50
+ # если фильтруем по property
51
+ elsif prop_id.present?
52
+
53
+ # фиксируем property
54
+ property = Property.find(prop_id)
55
+
56
+ # работаем с ней, если только есть площади
57
+ if property.areas.count > 0
58
+
59
+ # обозначим диапазон фильтрации
60
+ area_created_at = Time.at(property.areas.first.created_at)
61
+ time_now = Time.now
62
+ # Rails.logger.debug("area_created_at = #{area_created_at}")
63
+ # Rails.logger.debug("time_now = #{time_now}")
64
+
65
+ # если подана нижняя граница диапазона и она позже, чем время создания самой первой площади объекта,
66
+ # выравниваем период рассчета коэф-та по этой нижней границе диапазона
67
+ if start_date.present?
68
+ start_date_tt = Time.parse(start_date)
69
+ if start_date_tt > area_created_at
70
+ used_start_date = start_date_tt
71
+ # Rails.logger.debug("start_date: используем аргумент: #{start_date_tt}")
72
+ else
73
+ used_start_date = area_created_at
74
+ # Rails.logger.debug("start_date: используем время рождения Площади: #{area_created_at}")
75
+ end
76
+ else
77
+ used_start_date = area_created_at
78
+ # Rails.logger.debug("start_date: используем время рождения Площади: #{area_created_at}")
79
+ end
80
+ used_start_date_str = used_start_date.strftime('%Y/%m/%d')
81
+
82
+ if end_date.present?
83
+ end_date_tt = Time.parse(end_date)
84
+ if end_date < time_now
85
+ used_end_date = end_date_tt
86
+ Rails.logger.debug("end_date: используем аргумент: #{end_date_tt}")
87
+ else
88
+ used_end_date = time_now
89
+ Rails.logger.debug("end_date: используем текущее время")
90
+ end
91
+ else
92
+ used_end_date = time_now
93
+ Rails.logger.debug("end_date: используем текущее время")
94
+ end
95
+ used_end_date_str = used_end_date.strftime('%Y/%m/%d')
96
+
97
+ # Rails.logger.debug("start_date = #{start_date}; end_date = #{end_date}; used_start_date = #{used_start_date}; used_end_date = #{used_end_date}")
98
+ # sevents = self.where(:area_id => area_id).where(:created_at => used_start_date..used_end_date)
99
+ pstats = self.where(:property_id => prop_id)
100
+ .where("created_at BETWEEN ? AND ?", used_start_date, used_end_date)
101
+
102
+ if atype_id.present?
103
+ pstats = pstats.where(:atype_id => atype_id)
104
+ end
105
+
106
+ # если в этот промежуток небыло событий - значит промежуток целиком попал в какое-то событие
107
+ # найдем его
108
+ # заодно поднимем вспомогательный флаг, который обработаем во view
109
+ mark_whole = false
110
+ if pstats.count == 0
111
+ pstats = [self.where(:property_id => prop_id).where("created_at < ?", used_start_date).last]
112
+ mark_whole = true
113
+ # sevents.each do |se|
114
+ # Rails.logger.debug "\t\t\t #{used_start_date - se.created_at}"
115
+ # end
116
+ end
117
+
118
+ # если сортируем по типу, то берём последнюю запись,
119
+ # иначе - берём последнюю запись с общими данными
120
+ if atype_id.nil?
121
+ free_areas_atnow = pstats.where(:atype_id => nil).last.free_areas
122
+ busy_areas_atnow = pstats.where(:atype_id => nil).last.busy_areas
123
+ else
124
+ free_areas_atnow = pstats.last.free_areas
125
+ busy_areas_atnow = pstats.last.busy_areas
126
+ end
127
+
128
+ Rails.logger.debug("\t\t atype_id = #{atype_id}")
129
+ Rails.logger.debug("\t\t free_areas_atnow = #{free_areas_atnow}")
130
+ Rails.logger.debug("\t\t busy_areas_atnow = #{busy_areas_atnow}")
131
+
132
+ # защищаемся от деления на ноль
133
+ if free_areas_atnow + busy_areas_atnow == 0
134
+ bcoef = 0.0
135
+ else
136
+ bcoef = busy_areas_atnow*1.0 / (free_areas_atnow + busy_areas_atnow) * 100.0
137
+ end
138
+
139
+ result[:busy_coef] = sprintf "%.2f%", bcoef
140
+ result[:comment] = "<abbr title='Период рассчёта занятости'>C #{used_start_date_str} по #{used_end_date_str}</abbr>"
141
+ result[:abbr] = 'Занятость объекта за указанный период'
142
+ result[:title] = "Статистика - Объект - #{property.title}"
143
+ result[:graph] = _parse_for_js_radial_graph(free_areas_atnow,busy_areas_atnow)
144
+ result[:graph_dynamic] = _parse_for_js_dynamic_graph(pstats)
145
+
146
+ # if atype_id.present?
147
+ # result[:title] += " (#{Atype.find(atype_id).title})"
148
+ # end
149
+
150
+ dc_str = property.areas.first.created_at.in_time_zone('Moscow').strftime('%Y/%m/%d')
151
+ dc_abbr = 'За дату создания объекта недвижимости при рассчетах берётся дата создания первой площади объекта'
152
+
153
+ result[:props] = [
154
+ {tag: 'title', val: "#{property.title}"},
155
+ {tag: 'born_date', val: "<abbr title='#{dc_abbr}'>Дата создания: #{dc_str}"},
156
+ {tag: 'all_areas_count', val: "<abbr title='В конце указанного периода'>Площадей всего</abbr>: #{ free_areas_atnow + busy_areas_atnow }"},
157
+ {tag: 'free_areas_count', val: "<abbr title='В конце указанного периода'>Свободных площадей</abbr>: #{ free_areas_atnow }"},
158
+ {tag: 'busy_areas_count', val: "<abbr title='В конце указанного периода'>Занятых площадей</abbr>: #{ busy_areas_atnow }"}
159
+ ]
160
+
161
+ if atype_id.present?
162
+ result[:props] << {tag: 'atype_filter', val: "Фильтр по типу площади: #{ Atype.find(atype_id).title }"}
163
+ end
164
+
165
+ else
166
+ result[:props] = [
167
+ {tag: 'title', val: "#{property.title} не имеет площадей"}
168
+ ]
169
+ end
170
+ end
171
+
172
+ result
173
+
174
+ end
175
+
176
+ def atype_title
177
+ res = "-"
178
+ if atype.present?
179
+ res = atype.title
180
+ end
181
+ res
182
+ end
183
+
184
+ def property_title
185
+ res = "-"
186
+ if property.present?
187
+ res = property.title
188
+ end
189
+ res
190
+ end
191
+
192
+ private
193
+
194
+ # Когда создаётся запись, посчитаем коэф-ты
195
+ def calc_busy_coefs
196
+ if self.property.areas.count > 0
197
+
198
+ # здесь считаем коэф-ты только для `записей с общими данными`
199
+ if self.atype.nil?
200
+
201
+ self.free_areas = self.property.areas.free_areas.count
202
+ self.busy_areas = self.property.areas.busy_areas.count
203
+ self.coef_busy = self.busy_areas / (self.free_areas + self.busy_areas) * 100
204
+
205
+ self.free_areas_sq = self.property.areas.free_areas_sq
206
+ self.busy_areas_sq = self.property.areas.busy_areas_sq
207
+ self.coef_busy_sq = self.busy_areas_sq / (self.free_areas_sq + self.busy_areas_sq) * 100
208
+
209
+ # здесь считаем коэф-ты для 'atype related записей'
210
+ else
211
+ self.free_areas = self.property.areas.where(:atype_id => self.atype.id).free_areas.count
212
+ self.busy_areas = self.property.areas.where(:atype_id => self.atype.id).busy_areas.count
213
+ self.coef_busy = (self.free_areas + self.busy_areas == 0) ? 0:self.busy_areas / (self.free_areas + self.busy_areas) * 100
214
+
215
+ self.free_areas_sq = self.property.areas.where(:atype_id => self.atype.id).free_areas_sq
216
+ self.busy_areas_sq = self.property.areas.where(:atype_id => self.atype.id).busy_areas_sq
217
+ self.coef_busy_sq = (self.free_areas_sq + self.busy_areas_sq == 0) ? 0:self.busy_areas_sq / (self.free_areas_sq + self.busy_areas_sq) * 100
218
+ end
219
+ end
220
+ end
221
+
222
+ # Когда создаётся `запись с общими данными` в таблице 'pstats', автоматически
223
+ # создаются `atype related записи` в кол-ве N шт с данными по каждому типу площади
224
+ # с такой же датой created_at
225
+ def generate_atype_pstats
226
+
227
+ # генерим только для `записей с общими данными`
228
+ if self.atype.nil?
229
+
230
+ # перебираем все типы
231
+ atypes = Atype.all
232
+ atypes.each do |atype|
233
+
234
+ # генерим atype related pstats, связываем их с Родителем
235
+ Pstat.create!({
236
+ atype_id: atype.id,
237
+ property_id: self.property.id,
238
+ sevent_id: self.sevent.id,
239
+ created_at: self.created_at,
240
+ parent_id: self.id
241
+ })
242
+
243
+ end
244
+
245
+ end
246
+ end
247
+
248
+ def self._parse_for_js_radial_graph(free_areas_atnow, busy_areas_atnow)
249
+ # res = [
250
+ # ['Year', 'Sales', 'Expenses'],
251
+ # ['2013', 1000, 400],
252
+ # ['2014', 1170, 460],
253
+ # ['2015', 660, 1120],
254
+ # ['2016/12/12', 1030, 540]
255
+ #
256
+ # ]
257
+ # [
258
+ # ['', ''],
259
+ # ['Свободно', 11],
260
+ # ['Занято', 2]
261
+ # ]
262
+
263
+ res = [['','']]
264
+ res << ['Свободно', free_areas_atnow]
265
+ res << ['Занято', busy_areas_atnow]
266
+ Rails.logger.debug "<_parse_for_js_radial_graph> res: #{res}"
267
+ res
268
+
269
+ end
270
+
271
+ def self._parse_for_js_dynamic_graph(pstats)
272
+ # res = [
273
+ # ['Year', 'Sales', 'Expenses'],
274
+ # ['2013', 1000, 400],
275
+ # ['2014', 1170, 460],
276
+ # ['2015', 660, 1120],
277
+ # ['2016/12/12', 1030, 540]
278
+ # ]
279
+
280
+ res = []
281
+ pstats.each do |pstat|
282
+ res << [ pstat.created_at.strftime('%Y/%m/%d'), pstat.coef_busy ]
283
+ end
284
+ res
285
+
286
+ end
287
+
288
+ end
289
+ end
@@ -5,6 +5,9 @@ module C80Estate
5
5
  belongs_to :property
6
6
  belongs_to :astatus
7
7
  belongs_to :auser, :polymorphic => true
8
+ has_many :pstats, :dependent => :destroy
9
+
10
+ after_create :generate_pstat
8
11
 
9
12
  =begin
10
13
  def self.all_areas
@@ -146,6 +149,10 @@ module C80Estate
146
149
  # sevents = self.where(:area_id => area_id).where(:created_at => used_start_date..used_end_date)
147
150
  sevents = self.where(:area_id => area_id).where("created_at BETWEEN ? AND ?", used_start_date, used_end_date)
148
151
 
152
+ # if atype_id.present?
153
+ # sevents = sevents.where(:atype_id => atype_id)
154
+ # end
155
+
149
156
  # если в этот промежуток небыло событий - значит промежуток целиком попал в какое-то событие
150
157
  # найдем его
151
158
  # заодно поднимем вспомогательный флаг, который обработаем во view
@@ -198,6 +205,12 @@ module C80Estate
198
205
  { tag: 'property_title', val: "Объект: #{area.property_title}" }
199
206
  ]
200
207
 
208
+ # if atype_id.present?
209
+ # result[:props] << {tag: 'atype_filter', val: "Фильтр по типу площади: #{ Atype.find(atype_id).title }"}
210
+ # end
211
+
212
+ elsif prop_id.present?
213
+
201
214
  end
202
215
 
203
216
  result
@@ -364,5 +377,19 @@ module C80Estate
364
377
  res
365
378
  end
366
379
 
380
+ protected
381
+
382
+ def generate_pstat
383
+
384
+ # pparams = {
385
+ # atype_id: nil,
386
+ # property_id: self.property_id,
387
+ # sevent_id: self.id,
388
+ # created_at: self.created_at
389
+ # }
390
+ # Pstat.create!(pparams)
391
+
392
+ end
393
+
367
394
  end
368
395
  end
@@ -1,4 +1,5 @@
1
1
  C80Estate::Engine.routes.draw do
2
2
  match '/estate/get_atype_propnames', :to => 'ajax#get_atype_propnames', :via => :post
3
3
  match '/estate/areas_ecoef', :to => 'ajax#areas_ecoef', :via => :post
4
+ match '/estate/properties_busy_coef', :to => 'ajax#properties_busy_coef', :via => :post
4
5
  end
@@ -0,0 +1,17 @@
1
+ class CreateC80EstatePstats < ActiveRecord::Migration
2
+ def change
3
+ create_table :c80_estate_pstats, :options => 'COLLATE=utf8_unicode_ci' do |t|
4
+ t.references :property, index: true
5
+ t.references :atype, index: true
6
+ t.references :sevent, index: true
7
+ t.references :parent, index: true
8
+ t.integer :free_areas
9
+ t.integer :busy_areas
10
+ t.integer :coef_busy
11
+ t.integer :free_areas_sq
12
+ t.integer :busy_areas_sq
13
+ t.integer :coef_busy_sq
14
+ t.timestamps
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module C80Estate
2
- VERSION = "0.1.0.2"
2
+ VERSION = "0.1.0.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: c80_estate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.2
4
+ version: 0.1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - C80609A
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-07-15 00:00:00.000000000 Z
11
+ date: 2016-07-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -70,10 +70,12 @@ files:
70
70
  - app/admin/c80_estate/atypes.rb
71
71
  - app/admin/c80_estate/prop_names.rb
72
72
  - app/admin/c80_estate/properties.rb
73
+ - app/admin/c80_estate/pstats.rb
73
74
  - app/admin/c80_estate/role_types.rb
74
75
  - app/admin/c80_estate/sevents.rb
75
76
  - app/admin/c80_estate/uoms.rb
76
77
  - app/assets/javascript/c80_estate/backend/admin/areas.js
78
+ - app/assets/javascript/c80_estate/backend/admin/pstats.js
77
79
  - app/assets/javascript/c80_estate/backend/admin/sevents.js
78
80
  - app/assets/javascript/c80_estate/backend/init.js
79
81
  - app/assets/javascript/c80_estate/backend/init_selectpicker.js
@@ -81,6 +83,7 @@ files:
81
83
  - app/assets/javascript/c80_estate/lib/jalert.js
82
84
  - app/assets/javascript/c80_estate_active_admin.js.coffee
83
85
  - app/assets/stylesheets/c80_estate/backend/admin_areas.scss
86
+ - app/assets/stylesheets/c80_estate/backend/admin_pstats.scss
84
87
  - app/assets/stylesheets/c80_estate/backend/admin_sevents.scss
85
88
  - app/assets/stylesheets/c80_estate/backend/admin_users.scss
86
89
  - app/assets/stylesheets/c80_estate/backend/common.scss
@@ -98,6 +101,7 @@ files:
98
101
  - app/models/c80_estate/pphoto.rb
99
102
  - app/models/c80_estate/prop_name.rb
100
103
  - app/models/c80_estate/property.rb
104
+ - app/models/c80_estate/pstat.rb
101
105
  - app/models/c80_estate/role.rb
102
106
  - app/models/c80_estate/role_type.rb
103
107
  - app/models/c80_estate/sevent.rb
@@ -125,6 +129,7 @@ files:
125
129
  - db/migrate/20160704050000_create_c80_estate_role_types.rb
126
130
  - db/migrate/20160704063131_create_c80_estate_roles.rb
127
131
  - db/migrate/20160713043333_create_c80_estate_sevents.rb
132
+ - db/migrate/20160717094647_create_c80_estate_pstats.rb
128
133
  - db/seeds/50_fill_uoms.rb.example
129
134
  - db/seeds/55_fill_prop_names.rb.example
130
135
  - db/seeds/60_fill_atypes.rb.example