c80_estate 0.1.0.2 → 0.1.0.3

Sign up to get free protection for your applications and to get access to all the features.
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