c80_yax 0.1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|