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 +4 -4
- data/app/admin/c80_estate/pstats.rb +37 -0
- data/app/admin/c80_estate/sevents.rb +3 -1
- data/app/assets/javascript/c80_estate/backend/admin/pstats.js +219 -0
- data/app/assets/stylesheets/c80_estate/backend/admin_pstats.scss +131 -0
- data/app/assets/stylesheets/c80_estate/backend/admin_sevents.scss +4 -0
- data/app/controllers/c80_estate/ajax_controller.rb +26 -1
- data/app/models/c80_estate/area.rb +88 -20
- data/app/models/c80_estate/atype.rb +2 -0
- data/app/models/c80_estate/property.rb +1 -0
- data/app/models/c80_estate/pstat.rb +289 -0
- data/app/models/c80_estate/sevent.rb +27 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20160717094647_create_c80_estate_pstats.rb +17 -0
- data/lib/c80_estate/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 347ae43df7eb3ed899e9ae21f3a85648fff17baa
|
4
|
+
data.tar.gz: 38e409296f4dd3fb71867a38918da9c68823b678
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 { |
|
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
|
+
}
|
@@ -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,
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
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 =
|
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
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
@@ -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
|
data/config/routes.rb
CHANGED
@@ -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
|
data/lib/c80_estate/version.rb
CHANGED
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.
|
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-
|
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
|