c80_yax 0.1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +2 -0
- data/app/admin/c80_yax/items.rb +128 -0
- data/app/admin/c80_yax/prop_names.rb +90 -0
- data/app/admin/c80_yax/strsubcats.rb +128 -0
- data/app/admin/c80_yax/uoms.rb +35 -0
- data/app/admin/c80_yax/x_c80_yax.rb +5 -0
- data/app/assets/javascripts/backend/items.js +416 -0
- data/app/assets/javascripts/c80_yax.js.coffee +6 -0
- data/app/assets/javascripts/lib_backend/collapsable-groups.js +22 -0
- data/app/assets/javascripts/lib_backend/jalert.js +16 -0
- data/app/assets/stylesheets/c80_yax/backend/active_admin/admin_items.scss +152 -0
- data/app/assets/stylesheets/c80_yax/backend/collapsed.scss +56 -0
- data/app/assets/stylesheets/c80_yax/backend/jquery-my-dialog.scss +22 -0
- data/app/assets/stylesheets/c80_yax/lib/loading.scss +13 -0
- data/app/assets/stylesheets/c80_yax/mixins.scss +89 -0
- data/app/assets/stylesheets/c80_yax_backend.scss +7 -0
- data/app/controllers/c80_yax/admin_data_controller.rb +22 -0
- data/app/controllers/c80_yax/app_controller.rb +6 -0
- data/app/helpers/c80_yax/data_helper.rb +84 -0
- data/app/models/c80_yax/iphoto.rb +7 -0
- data/app/models/c80_yax/item.rb +169 -0
- data/app/models/c80_yax/item_prop.rb +83 -0
- data/app/models/c80_yax/prop.rb +5 -0
- data/app/models/c80_yax/prop_name.rb +32 -0
- data/app/models/c80_yax/strsubcat.rb +71 -0
- data/app/models/c80_yax/uom.rb +5 -0
- data/app/uploaders/c80_yax/iphoto_uploader.rb +41 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/c80_yax.gemspec +26 -0
- data/config/locales/ru.yml +52 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20161030061203_create_c80_yax_strsubcats.rb +12 -0
- data/db/migrate/20161030225354_create_c80_yax_items.rb +20 -0
- data/db/migrate/20161107202727_create_c80_yax_iphotos.rb +11 -0
- data/db/migrate/20161107210000_create_c80_yax_props.rb +15 -0
- data/db/migrate/20161108095505_create_c80_yax_uoms.rb +11 -0
- data/db/migrate/20161108095950_create_c80_yax_prop_names.rb +13 -0
- data/db/migrate/20161108100707_create_c80_yax_join_table_prop_names_strsubcats.rb +12 -0
- data/db/migrate/20161108102828_create_c80_yax_item_props.rb +13 -0
- data/db/seeds/c80_yax_01_fill_props.rb +11 -0
- data/lib/c80_yax/engine.rb +23 -0
- data/lib/c80_yax/version.rb +3 -0
- data/lib/c80_yax.rb +8 -0
- metadata +135 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
#loading {
|
2
|
+
position: fixed;
|
3
|
+
top: 0;
|
4
|
+
left: 0;
|
5
|
+
bottom: 0;
|
6
|
+
right: 0;
|
7
|
+
text-align: center;
|
8
|
+
font-size: 20px;
|
9
|
+
background: rgba(255,255,255,0.7) url(data:image/gif;base64,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) 50% 50% no-repeat;
|
10
|
+
z-index: 9999;
|
11
|
+
border-radius: 5px;
|
12
|
+
line-height: 3;
|
13
|
+
}
|
@@ -0,0 +1,89 @@
|
|
1
|
+
// тень
|
2
|
+
@mixin shdw($val) {
|
3
|
+
-webkit-box-shadow: 0 0 7px 0 rgba(0, 0, 0, $val);
|
4
|
+
-moz-box-shadow: 0 0 7px 0 rgba(0, 0, 0, $val);
|
5
|
+
box-shadow: 0 0 7px 0 rgba(0, 0, 0, $val);
|
6
|
+
/* For IE 8 */
|
7
|
+
-ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=$val, Direction=135, Color='#000000')";
|
8
|
+
/* For IE 5.5 - 7 */
|
9
|
+
filter: progid:DXImageTransform.Microsoft.Shadow(Strength=$val, Direction=135, Color='#000000');
|
10
|
+
}
|
11
|
+
|
12
|
+
@mixin clearfx() {
|
13
|
+
&:before,
|
14
|
+
&:after {
|
15
|
+
content: " ";
|
16
|
+
display: table;
|
17
|
+
}
|
18
|
+
&:after {
|
19
|
+
clear: both;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
// ссылка без подчёркивания и обводки
|
24
|
+
//@mixin nounder {
|
25
|
+
// text-decoration: none !important;
|
26
|
+
// border: none !important;
|
27
|
+
// outline: none !important;
|
28
|
+
//
|
29
|
+
// &:hover, &:active, &:focus {
|
30
|
+
// text-decoration: none !important;
|
31
|
+
// border: none !important;
|
32
|
+
// outline: none !important;
|
33
|
+
// }
|
34
|
+
//}
|
35
|
+
|
36
|
+
// анимированный переход цвета
|
37
|
+
//@mixin transition_color($sec) {
|
38
|
+
// -webkit-transition: color $sec ease-out;
|
39
|
+
// -moz-transition: color $sec ease-out;
|
40
|
+
// -ms-transition: color $sec ease-out;
|
41
|
+
// -o-transition: color $sec ease-out;
|
42
|
+
// transition: color $sec ease-out;
|
43
|
+
//}
|
44
|
+
|
45
|
+
// анимированный переход цвета границы
|
46
|
+
//@mixin transition_border_color($sec) {
|
47
|
+
// -webkit-transition: border-color $sec ease-in;
|
48
|
+
// -moz-transition: border-color $sec ease-in;
|
49
|
+
// -ms-transition: border-color $sec ease-in;
|
50
|
+
// -o-transition: border-color $sec ease-in;
|
51
|
+
// transition: border-color $sec ease-in;
|
52
|
+
//}
|
53
|
+
|
54
|
+
//@mixin transform_prop($prop_name,$sec) {
|
55
|
+
// -webkit-transition: $prop_name $sec ease-out;
|
56
|
+
// -moz-transition: $prop_name $sec ease-out;
|
57
|
+
// -ms-transition: $prop_name $sec ease-out;
|
58
|
+
// -o-transition: $prop_name $sec ease-out;
|
59
|
+
// transition: $prop_name $sec ease-out;
|
60
|
+
//}
|
61
|
+
|
62
|
+
// градиент сверху-вниз
|
63
|
+
//@mixin bg_tobottom_gradient($from,$to) {
|
64
|
+
// background-image: linear-gradient(to bottom, $from, $to) !important;
|
65
|
+
// background: -webkit-gradient(linear, left top, left bottom, from($from), to($to));
|
66
|
+
// filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='$from', endColorstr='$to', GradientType=0);
|
67
|
+
//}
|
68
|
+
|
69
|
+
//@mixin transform_scale($scale,$time) {
|
70
|
+
// -webkit-transform: scale($scale);
|
71
|
+
// -moz-transform: scale($scale);
|
72
|
+
// -ms-transform: scale($scale);
|
73
|
+
// -o-transform: scale($scale);
|
74
|
+
// transform: scale($scale);
|
75
|
+
//
|
76
|
+
// -webkit-transition: -webkit-transform $time ease-out;
|
77
|
+
// -moz-transition: -moz-transform $time ease-out;
|
78
|
+
// -ms-transition: -ms-transform $time ease-out;
|
79
|
+
// -o-transition: -o-transform $time ease-out;
|
80
|
+
// transition: transform $time ease-out;
|
81
|
+
//}
|
82
|
+
|
83
|
+
//@mixin opacity($val) {
|
84
|
+
// -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$val)";
|
85
|
+
// filter: alpha(opacity=$val);
|
86
|
+
// -moz-opacity:$val;
|
87
|
+
// -khtml-opacity: $val;
|
88
|
+
// opacity: $val;
|
89
|
+
//}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module C80Yax
|
2
|
+
class AdminDataController < ApplicationController
|
3
|
+
|
4
|
+
# http://stackoverflow.com/questions/5130150/rails-how-to-use-a-helper-inside-a-controller
|
5
|
+
include DataHelper
|
6
|
+
|
7
|
+
def get_strsubcat_propnames
|
8
|
+
Rails.logger.debug '[TRACE] <admin_data_controller.get_strsubcat_propnames> Получить список имён свойств данной подкатегории.'
|
9
|
+
Rails.logger.debug "[TRACE] <admin_data_controller.get_strsubcat_propnames> request: #{request.request_parameters}"
|
10
|
+
|
11
|
+
strsubcat_id = request.params[:strsubcat_id]
|
12
|
+
|
13
|
+
obj = stdh_get_strsubcat_propnames(strsubcat_id)
|
14
|
+
|
15
|
+
respond_to do |format|
|
16
|
+
format.js { render json: obj, status: :ok }
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module C80Yax
|
2
|
+
|
3
|
+
# хелпер, помогающий с выборкой данных для товаров из категории "строительные материалы"
|
4
|
+
module DataHelper
|
5
|
+
|
6
|
+
include ActiveRecord
|
7
|
+
|
8
|
+
# собрать все значения свойства prop_name_id из подкатегории sub_cat
|
9
|
+
def stdh_collect_all_values(prop_name_id, sub_cat_id)
|
10
|
+
|
11
|
+
# +---------------------+
|
12
|
+
# | prop_23 |
|
13
|
+
# +---------------------+
|
14
|
+
# | 215 x 102 x 65 мм |
|
15
|
+
# | 215 x 48 x 65 мм |
|
16
|
+
# | 250 x 85 x 65 мм |
|
17
|
+
# | 254 x 95 x 65 мм |
|
18
|
+
# | 290 x 90 x 52 мм |
|
19
|
+
# | 528 x 108 x 37 мм |
|
20
|
+
# +---------------------+
|
21
|
+
|
22
|
+
table_name = "strcat_#{sub_cat_id}_items"
|
23
|
+
column_name = "prop_#{prop_name_id}"
|
24
|
+
|
25
|
+
sql = "
|
26
|
+
SELECT #{table_name}.#{column_name}
|
27
|
+
FROM #{table_name}
|
28
|
+
GROUP by #{table_name}.#{column_name};
|
29
|
+
"
|
30
|
+
|
31
|
+
ActiveRecord::Base.connection.execute(sql) # => records array
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
# выдать все характеристики, присущие данной категории, вместе с единицами измерений
|
36
|
+
def stdh_get_strsubcat_propnames(strsubcat_id)
|
37
|
+
|
38
|
+
# +----+----------------+----------------------------+-----------+
|
39
|
+
# | id | title | is_excluded_from_filtering | uom_title |
|
40
|
+
# +----+----------------+----------------------------+-----------+
|
41
|
+
# | 2 | Цена | 0 | руб. |
|
42
|
+
# | 3 | Объём | 0 | мл |
|
43
|
+
# | 4 | Вкус | 0 | NULL |
|
44
|
+
# | 5 | VG/PG | 0 | NULL |
|
45
|
+
# | 6 | Никотин | 0 | мг |
|
46
|
+
# | 7 | Страна | 0 | NULL |
|
47
|
+
# | 19 | Бренд | 0 | NULL |
|
48
|
+
# +----+----------------+----------------------------+-----------+
|
49
|
+
|
50
|
+
# {"id"=>2, "title"=>"Цена", "is_excluded_from_filtering"=>0, "uom_title"=>"руб."},
|
51
|
+
# {"id"=>3, "title"=>"Объём", "is_excluded_from_filtering"=>0, "uom_title"=>"мл"},
|
52
|
+
# {"id"=>4, "title"=>"Вкус", "is_excluded_from_filtering"=>0, "uom_title"=>nil},
|
53
|
+
# {"id"=>5, "title"=>"VG/PG", "is_excluded_from_filtering"=>0, "uom_title"=>nil},
|
54
|
+
# {"id"=>6, "title"=>"Никотин", "is_excluded_from_filtering"=>0, "uom_title"=>"мг"},
|
55
|
+
# {"id"=>7, "title"=>"Страна", "is_excluded_from_filtering"=>0, "uom_title"=>nil},
|
56
|
+
# {"id"=>19, "title"=>"Бренд", "is_excluded_from_filtering"=>0, "uom_title"=>nil}
|
57
|
+
|
58
|
+
Rails.logger.debug '[TRACE] <stdh_get_strsubcat_propnames> BEGIN'
|
59
|
+
sql = "
|
60
|
+
SELECT
|
61
|
+
`c80_yax_prop_names`.`id`,
|
62
|
+
`c80_yax_prop_names`.`title`,
|
63
|
+
`c80_yax_prop_names`.`is_excluded_from_filtering`,
|
64
|
+
`c80_yax_uoms`.`title` as `uom_title`
|
65
|
+
FROM `c80_yax_prop_names`
|
66
|
+
INNER JOIN `c80_yax_prop_names_strsubcats` ON `c80_yax_prop_names`.`id` = `c80_yax_prop_names_strsubcats`.`prop_name_id`
|
67
|
+
LEFT OUTER JOIN `c80_yax_uoms` ON `c80_yax_uoms`.`id` = `c80_yax_prop_names`.`uom_id`
|
68
|
+
WHERE `c80_yax_prop_names_strsubcats`.`strsubcat_id` = #{strsubcat_id};
|
69
|
+
"
|
70
|
+
|
71
|
+
result = []
|
72
|
+
rows = Base.connection.execute(sql)
|
73
|
+
rows.each(:as => :hash) do |row|
|
74
|
+
result << row
|
75
|
+
end
|
76
|
+
|
77
|
+
Rails.logger.debug '[TRACE] <stdh_get_strsubcat_propnames> END'
|
78
|
+
result
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'babosa'
|
2
|
+
|
3
|
+
class C80Yax::Item < ActiveRecord::Base
|
4
|
+
|
5
|
+
validates :title,
|
6
|
+
presence: true,
|
7
|
+
uniqueness: true,
|
8
|
+
length: { in: 2..150 }
|
9
|
+
|
10
|
+
validates :strsubcat,
|
11
|
+
presence: true
|
12
|
+
|
13
|
+
# has_and_belongs_to_many :vendors
|
14
|
+
belongs_to :strsubcat
|
15
|
+
|
16
|
+
has_many :iphotos, :dependent => :destroy
|
17
|
+
accepts_nested_attributes_for :iphotos,
|
18
|
+
:reject_if => lambda { |attributes|
|
19
|
+
!attributes.present?
|
20
|
+
},
|
21
|
+
:allow_destroy => true
|
22
|
+
|
23
|
+
has_many :item_props, :dependent => :destroy
|
24
|
+
accepts_nested_attributes_for :item_props,
|
25
|
+
:reject_if => lambda { |attributes|
|
26
|
+
# puts "attributes:: #{attributes}"
|
27
|
+
# attributes:: {"value"=>"", "prop_name_id"=>""}
|
28
|
+
!attributes.present? || \
|
29
|
+
!attributes[:value].present? || \
|
30
|
+
!attributes[:prop_name_id].present?
|
31
|
+
},
|
32
|
+
:allow_destroy => true
|
33
|
+
|
34
|
+
has_many :related_childs, :class_name => 'C80Yax::Item', :foreign_key => 'related_parent_id'
|
35
|
+
belongs_to :related_parent, :class_name => 'C80Yax::Item'
|
36
|
+
|
37
|
+
extend FriendlyId
|
38
|
+
friendly_id :slug_candidates, :use => :slugged
|
39
|
+
|
40
|
+
def slug_candidates
|
41
|
+
[:title] + Array.new(6) {|index| [:title, index+2]}
|
42
|
+
end
|
43
|
+
|
44
|
+
def normalize_friendly_id(input)
|
45
|
+
input.to_s.to_slug.normalize(transliterations: :russian).to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
# выдать все товары, которые надо показать на главной странице "строительные материалы"
|
52
|
+
# с помощью методов ActiveRecord
|
53
|
+
def self.all_on_main_ar
|
54
|
+
|
55
|
+
# * В первую очередь отображаются товары с пометкой "Выводится на главной"
|
56
|
+
items_is_main = self.where('is_main = ?',1)
|
57
|
+
|
58
|
+
# * Далее во вторую очередь выводятся товары, у которых есть обе отметки "hit" и "sale"
|
59
|
+
items_is_hit_and_is_sale = self.where('is_hit = ? AND is_sale = ?',1,1)
|
60
|
+
|
61
|
+
# * Далее выводятся товары, которые отмечены только "hit"
|
62
|
+
items_is_hit = self.where('is_hit = ? AND is_sale = ?',1,0)
|
63
|
+
|
64
|
+
# * Потом товары, которые отмечены только sale
|
65
|
+
items_is_sale = self.where('is_sale = ? AND is_hit = ?',1,0)
|
66
|
+
|
67
|
+
# * А далее все товары, которые по цене (по возрастанию) - от наиболее дешевого товара к наиболее дорогому.
|
68
|
+
items_other = self.where.not('is_main = ?',1)
|
69
|
+
.where.not('is_hit = ? AND is_sale = ?',1,1)
|
70
|
+
.where.not('is_hit = ?',1)
|
71
|
+
.where.not('is_sale = ?',1)
|
72
|
+
|
73
|
+
items_is_main.union(items_is_hit_and_is_sale)
|
74
|
+
.union(items_is_hit)
|
75
|
+
.union(items_is_sale)
|
76
|
+
.union(items_other)
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
# выдать все товары, которые надо показать на любой странице подкатегории (БЕЗ ФИЛЬТРОВ)
|
81
|
+
# с помощью методов ActiveRecord и c80_active_record_union
|
82
|
+
def self.all_on_subcat_ar(strsubcat_id)
|
83
|
+
|
84
|
+
# Сначала выводятся только те, товары, у которых есть обе отметки "hit" и "sale"
|
85
|
+
items_is_hit_and_is_sale = self.where('is_hit = ? AND is_sale = ?',1,1)
|
86
|
+
|
87
|
+
# * Далее выводятся товары, которые отмечены только "hit"
|
88
|
+
items_is_hit = self.where('is_hit = ? AND is_sale = ?',1,0)
|
89
|
+
|
90
|
+
# * Потом товары, которые отмечены только sale
|
91
|
+
items_is_sale = self.where('is_sale = ? AND is_hit = ?',1,0)
|
92
|
+
|
93
|
+
# * А далее все товары, которые по цене (по возрастанию) - от наиболее дешевого товара к наиболее дорогому.
|
94
|
+
items_other = self.where.not('is_main = ?',1)
|
95
|
+
.where.not('is_hit = ? AND is_sale = ?',1,1)
|
96
|
+
.where.not('is_hit = ?',1)
|
97
|
+
.where.not('is_sale = ?',1)
|
98
|
+
|
99
|
+
items_is_hit_and_is_sale.union(items_is_hit)
|
100
|
+
.union(items_is_sale)
|
101
|
+
.union(items_other)
|
102
|
+
.where(:strsubcat_id => strsubcat_id)
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
before_save :before_save_format_desc
|
107
|
+
|
108
|
+
# сформировать и вернуть список "похожих товаров"
|
109
|
+
def self.get_related_items_list(item_id)
|
110
|
+
# Rails.logger.debug("<Item.get_related_items_list> [123] item_id = #{item_id}")
|
111
|
+
# Он формируется по следующим правилам:
|
112
|
+
# 1. Попадают товары из этой же подкатегории (обязательно, если в подкатегории один товар, то блока просто нет)
|
113
|
+
# 2. Тот же бренд
|
114
|
+
# 3. Наиболее близкая цена
|
115
|
+
# 4. Если есть параметр "Размер", то наиболее близкие по размеру.
|
116
|
+
# Также должа быть возможность ручного управления блоком "Похожие товары",
|
117
|
+
# где администратор просто указывает ссылки на похожие товары.
|
118
|
+
|
119
|
+
# результат
|
120
|
+
all_related_items = []
|
121
|
+
|
122
|
+
# кол-во элементов в результате не более этого значения
|
123
|
+
n = 4
|
124
|
+
|
125
|
+
item = self.find(item_id)
|
126
|
+
|
127
|
+
if item.related_childs.count > 0
|
128
|
+
item.related_childs.each do |itm|
|
129
|
+
if all_related_items.count < n
|
130
|
+
all_related_items << itm
|
131
|
+
else
|
132
|
+
break
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
all_related_items
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def before_save_format_desc
|
144
|
+
if self.full_desc.present?
|
145
|
+
v = self.full_desc
|
146
|
+
|
147
|
+
# удаляем inline css стили
|
148
|
+
v = v.gsub(/ style=["'][^"']+["']/, '')
|
149
|
+
|
150
|
+
# удаляем тэг <font>
|
151
|
+
v = v.gsub(/<font[^>]*>/, '')
|
152
|
+
v = v.gsub('</font>', '')
|
153
|
+
|
154
|
+
# <strong>...</strong> заменяем на <span class='bold'>...</span>
|
155
|
+
v = v.gsub(/<(em|strong)>/, '<span class="bold">')
|
156
|
+
v = v.gsub(/<\/(em|strong)>/, '</span>')
|
157
|
+
|
158
|
+
# заголовки h1, h2, h3 заменяем на h4
|
159
|
+
v = v.gsub(/<(h1|h2|h3)>/, '<h4>')
|
160
|
+
v = v.gsub(/<\/(h1|h2|h3)>/, '<h4>')
|
161
|
+
|
162
|
+
v = v.gsub(' ', ' ')
|
163
|
+
|
164
|
+
self.full_desc = v
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module C80Yax
|
2
|
+
class ItemProp < ActiveRecord::Base
|
3
|
+
belongs_to :item
|
4
|
+
belongs_to :prop_name
|
5
|
+
|
6
|
+
before_save :before_save_format_value
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def self.capz
|
11
|
+
[24, # страна
|
12
|
+
36, # бренд
|
13
|
+
46] # бренд (старый)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.uppz
|
17
|
+
[26, # коэф-т теплопроводности
|
18
|
+
27, # морозостойкость
|
19
|
+
38, # формат
|
20
|
+
80, # Марка прочности кирпича (дубликат, созданный заказчиком)
|
21
|
+
75] # марка прочности
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.do_not_touch
|
25
|
+
[
|
26
|
+
78, # Завод производитель
|
27
|
+
]
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.siz
|
31
|
+
[23] # размер
|
32
|
+
end
|
33
|
+
|
34
|
+
def before_save_format_value
|
35
|
+
|
36
|
+
v = self.value
|
37
|
+
uom = prop_name.uom
|
38
|
+
|
39
|
+
# удаляем пробелы в начале и в конце строки
|
40
|
+
v = v.strip! || v
|
41
|
+
|
42
|
+
# числовые значения преобразуем в числа
|
43
|
+
if uom.present? && uom.is_number
|
44
|
+
|
45
|
+
v = v.gsub(' ', '')
|
46
|
+
v = v.gsub(',', '.')
|
47
|
+
v = v[/([0-9.]+)/]
|
48
|
+
|
49
|
+
# нечисловые значения: либо capitalize, либо upcase, либо downcase
|
50
|
+
else
|
51
|
+
|
52
|
+
if prop_name_id.in?(ItemProp.capz)
|
53
|
+
v = v.mb_chars.capitalize.to_s
|
54
|
+
elsif prop_name_id.in?(ItemProp.uppz)
|
55
|
+
v = v.mb_chars.upcase.to_s
|
56
|
+
elsif prop_name_id.in?(ItemProp.do_not_touch)
|
57
|
+
v = v
|
58
|
+
else
|
59
|
+
v = v.mb_chars.downcase.to_s
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
if prop_name_id.in?(ItemProp.siz)
|
65
|
+
v = v.gsub(',', '.')
|
66
|
+
sizes = v.scan(/([0-9,]+)/)
|
67
|
+
oum = v.scan(/[мс]*м/)
|
68
|
+
v = sizes.join(" x ")
|
69
|
+
if oum.count > 0
|
70
|
+
v += " #{oum[0]}"
|
71
|
+
else
|
72
|
+
v += ' мм'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
self.value = v
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module C80Yax
|
2
|
+
class PropName < ActiveRecord::Base
|
3
|
+
|
4
|
+
validates :title,
|
5
|
+
presence: true,
|
6
|
+
uniqueness: true,
|
7
|
+
length: { in: 2..150 }
|
8
|
+
|
9
|
+
# has_many :item_props, :dependent => :destroy
|
10
|
+
# has_and_belongs_to_many :strsubcats
|
11
|
+
belongs_to :uom
|
12
|
+
accepts_nested_attributes_for :uom
|
13
|
+
|
14
|
+
has_many :im_old_price_and_this_is_link_to_my_normal_price, # NOTE:: поправить, как дойдёт дело
|
15
|
+
class_name: 'C80Yax::ItemProp',
|
16
|
+
foreign_key: 'related_id'
|
17
|
+
|
18
|
+
# для цены можно указать старую цену (если она есть)
|
19
|
+
belongs_to :related,
|
20
|
+
class_name: 'C80Yax::ItemProp'
|
21
|
+
|
22
|
+
# has_and_belongs_to_many :main_props
|
23
|
+
# has_and_belongs_to_many :common_props
|
24
|
+
# has_and_belongs_to_many :price_props
|
25
|
+
|
26
|
+
default_scope {order(:title => :asc)}
|
27
|
+
|
28
|
+
# validates_with PropNameValidator
|
29
|
+
# TODO:: добавить валидацию title на уникальность и длину
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'babosa'
|
2
|
+
|
3
|
+
class C80Yax::Strsubcat < ActiveRecord::Base
|
4
|
+
|
5
|
+
validates :title,
|
6
|
+
presence: true,
|
7
|
+
uniqueness: true,
|
8
|
+
length: { in: 6..50 }
|
9
|
+
|
10
|
+
has_many :subordinates,
|
11
|
+
class_name: 'C80Yax::Strsubcat',
|
12
|
+
foreign_key: 'parent_id'
|
13
|
+
|
14
|
+
belongs_to :parent,
|
15
|
+
class_name: 'C80Yax::Strsubcat'
|
16
|
+
|
17
|
+
has_and_belongs_to_many :prop_names#,
|
18
|
+
#:after_add => :after_add_prop_names,
|
19
|
+
#:after_remove => :after_remove_prop_names
|
20
|
+
|
21
|
+
has_many :items, :dependent => :destroy
|
22
|
+
|
23
|
+
# has_many :main_props, :dependent => :destroy
|
24
|
+
# accepts_nested_attributes_for :main_props,
|
25
|
+
# :reject_if => lambda { |attributes|
|
26
|
+
# !attributes.present?
|
27
|
+
# },
|
28
|
+
# :allow_destroy => true
|
29
|
+
#
|
30
|
+
# has_many :price_props, :dependent => :destroy
|
31
|
+
# accepts_nested_attributes_for :price_props,
|
32
|
+
# :reject_if => lambda { |attributes|
|
33
|
+
# !attributes.present?
|
34
|
+
# },
|
35
|
+
# :allow_destroy => true
|
36
|
+
#
|
37
|
+
# has_many :common_props, :dependent => :destroy
|
38
|
+
# accepts_nested_attributes_for :common_props,
|
39
|
+
# :reject_if => lambda { |attributes|
|
40
|
+
# !attributes.present?
|
41
|
+
# },
|
42
|
+
# :allow_destroy => true
|
43
|
+
|
44
|
+
extend FriendlyId
|
45
|
+
friendly_id :slug_candidates, :use => :slugged
|
46
|
+
|
47
|
+
def slug_candidates
|
48
|
+
[:title] + Array.new(6) {|index| [:title, index+2]}
|
49
|
+
end
|
50
|
+
|
51
|
+
def normalize_friendly_id(input)
|
52
|
+
input.to_s.to_slug.normalize(transliterations: :russian).to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
scope :menu_order, -> {order(:ord => :asc)}
|
56
|
+
|
57
|
+
# ------------------------------------------------------------------------------------------------------------------------
|
58
|
+
|
59
|
+
ransacker :parent_id,
|
60
|
+
formatter: proc { |v|
|
61
|
+
# Rails.logger.debug "[TRACE] <v> #{v}"
|
62
|
+
results = C80Yax::Strsubcat
|
63
|
+
.where(:parent_id => v)
|
64
|
+
.map(&:id)
|
65
|
+
# Rails.logger.debug "[TRACE] <results> #{results}"
|
66
|
+
results = results.present? ? results : nil
|
67
|
+
}, splat_params: true do |parent|
|
68
|
+
parent.table[:id]
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module C80Yax
|
2
|
+
|
3
|
+
# грузит картинку услуги
|
4
|
+
class IphotoUploader < BaseFileUploader
|
5
|
+
|
6
|
+
process :resize_to_limit => [1024,768]
|
7
|
+
|
8
|
+
version :thumb_sm do
|
9
|
+
begin
|
10
|
+
p = C80Yax::Prop.first
|
11
|
+
process :resize_to_fill => [p.thumb_sm_width, p.thumb_sm_height]
|
12
|
+
rescue => e
|
13
|
+
Rails.logger.debug "[TRACE] <iphoto_uploader.thumb_sm> [ERROR] #{e}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
version :thumb_md do
|
18
|
+
begin
|
19
|
+
p = C80Yax::Prop.first
|
20
|
+
process :resize_to_fill => [p.thumb_md_width, p.thumb_md_height]
|
21
|
+
rescue => e
|
22
|
+
Rails.logger.debug "[TRACE] <iphoto_uploader.thumb_md> [ERROR] #{e}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
version :thumb_lg do
|
27
|
+
begin
|
28
|
+
p = C80Yax::Prop.first
|
29
|
+
process :resize_to_fill => [p.thumb_lg_width, p.thumb_lg_height]
|
30
|
+
rescue => e
|
31
|
+
Rails.logger.debug "[TRACE] <iphoto_uploader.thumb_lg> [ERROR] #{e}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def store_dir
|
36
|
+
'uploads/items'
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "c80_yax"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|