c80_yax 0.1.0.1 → 0.1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/README.md +50 -13
  5. data/app/admin/c80_yax/cats.rb +47 -0
  6. data/app/admin/c80_yax/items.rb +36 -30
  7. data/app/admin/c80_yax/lib/custom_columns.rb +37 -0
  8. data/app/admin/c80_yax/prop_names.rb +13 -9
  9. data/app/admin/c80_yax/strsubcats.rb +114 -57
  10. data/app/admin/c80_yax/vendors.rb +39 -0
  11. data/app/assets/javascripts/backend/items.js +1 -1
  12. data/app/assets/javascripts/backend/strsubcats.js +26 -0
  13. data/app/assets/javascripts/c80_yax.js.coffee +3 -1
  14. data/app/assets/javascripts/lib_backend/custom_columns.js +73 -0
  15. data/app/assets/javascripts/lib_backend/init.js +28 -0
  16. data/app/assets/javascripts/lib_backend/loading.js +8 -0
  17. data/app/assets/stylesheets/c80_yax/_mixins/_colors.scss +1 -0
  18. data/app/assets/stylesheets/c80_yax/_mixins/color_button.scss +31 -0
  19. data/app/assets/stylesheets/c80_yax/_mixins/shdw.scss +10 -0
  20. data/app/assets/stylesheets/c80_yax/backend/active_admin/admin_items.scss +1 -1
  21. data/app/assets/stylesheets/c80_yax/backend/collapsed.scss +1 -1
  22. data/app/assets/stylesheets/c80_yax/elems/add_to_bucket.scss +11 -0
  23. data/app/assets/stylesheets/c80_yax/lib/bootstrap_checkboxes.scss +58 -0
  24. data/app/assets/stylesheets/c80_yax/lib_custom/bootstrap_checkboxes.scss +6 -0
  25. data/app/assets/stylesheets/c80_yax.scss +1 -0
  26. data/app/assets/stylesheets/c80_yax_backend.scss +2 -1
  27. data/app/helpers/c80_yax/items/asterix_helper.rb +13 -0
  28. data/app/helpers/c80_yax/items/buy_options_helper.rb +33 -0
  29. data/app/helpers/c80_yax/items/item_view_helper.rb +24 -0
  30. data/app/helpers/c80_yax/items/photos/item_photos_helper.rb +43 -0
  31. data/app/helpers/c80_yax/items/render_show_item_helper.rb +17 -0
  32. data/app/helpers/c80_yax/prop_name_helper.rb +11 -0
  33. data/app/helpers/c80_yax/strsubcats/props_helper.rb +81 -0
  34. data/app/helpers/c80_yax/uom_helper.rb +19 -0
  35. data/app/models/c80_yax/cat.rb +25 -0
  36. data/app/models/c80_yax/common_prop.rb +51 -0
  37. data/app/models/c80_yax/concerns/props/parsable.rb +129 -0
  38. data/app/models/c80_yax/item.rb +3 -1
  39. data/app/models/c80_yax/item_observer.rb +29 -0
  40. data/app/models/c80_yax/main_prop.rb +37 -0
  41. data/app/models/c80_yax/mixins/item/database/props.rb +66 -0
  42. data/app/models/c80_yax/mixins/strsubcat/database/prop_names_changed.rb +56 -0
  43. data/app/models/c80_yax/mixins/strsubcat/database/props.rb +37 -0
  44. data/app/models/c80_yax/prefix_prop.rb +35 -0
  45. data/app/models/c80_yax/price_prop.rb +47 -0
  46. data/app/models/c80_yax/prop_name.rb +4 -4
  47. data/app/models/c80_yax/strsubcat.rb +38 -23
  48. data/app/models/c80_yax/strsubcat_observer.rb +47 -0
  49. data/app/models/c80_yax/vendor.rb +16 -0
  50. data/app/views/admin/strsubcats/_view.html.erb +40 -0
  51. data/app/views/c80_yax/items/_buy_options.html.erb +9 -0
  52. data/c80_yax.gemspec +3 -0
  53. data/config/locales/ru.yml +33 -6
  54. data/db/migrate/20161030225354_create_c80_yax_items.rb +2 -0
  55. data/db/migrate/20170620111100_create_c80_yax_cats.rb +11 -0
  56. data/db/migrate/20170620111401_create_c80_yax_join_table_cats_strsubcats.rb +12 -0
  57. data/db/migrate/20170620164848_create_c80_yax_price_props.rb +9 -0
  58. data/db/migrate/20170620164949_create_c80_yax_join_table_price_props_prop_names.rb +12 -0
  59. data/db/migrate/20170620183838_create_c80_yax_main_props.rb +8 -0
  60. data/db/migrate/20170620195757_create_c80_yax_join_table_main_props_prop_names.rb +12 -0
  61. data/db/migrate/20170620200707_create_c80_yax_common_props.rb +8 -0
  62. data/db/migrate/20170620200808_create_c80_yax_join_table_common_props_prop_names.rb +12 -0
  63. data/db/migrate/20170621170202_create_c80_yax_prefix_props.rb +8 -0
  64. data/db/migrate/20170621170808_create_c80_yax_join_table_prefix_props_prop_names.rb +12 -0
  65. data/db/migrate/20170622193535_create_c80_yax_vendors.rb +11 -0
  66. data/db/migrate/20170622194040_create_c80_yax_join_table_items_vendors.rb +12 -0
  67. data/lib/c80_yax/engine.rb +2 -0
  68. data/lib/c80_yax/strsubcat_runtime_tables.rb +668 -0
  69. data/lib/c80_yax/version.rb +1 -1
  70. data/lib/c80_yax.rb +4 -2
  71. data/lib/generators/c80_yax/install_generator.rb +20 -0
  72. data/lib/generators/c80_yax/templates/app/helpers/c80_yax/items/show_item_helper.rb +21 -0
  73. metadata +98 -4
  74. data/app/assets/stylesheets/c80_yax/mixins.scss +0 -89
@@ -0,0 +1,668 @@
1
+ # В задачи класса входят:
2
+ #
3
+ # * создавать
4
+ # * уничтожать
5
+ # * заполнять
6
+ # * обновлять записи
7
+ #
8
+ # таблиц вида `c80_yax_strcat_#{NN}_items".
9
+
10
+ class StrsubcatRuntimeTables
11
+
12
+ def self.table_fill(strsubcat_id) # strh_table_fill
13
+
14
+ # NOTE:: [columns] эти столбцы должны соответствовать (комментарий как wiki)
15
+
16
+ # [0] item_props.prop_name_id,
17
+ # [1] prop_names.title AS prop_name_title,
18
+ # [2] item_props.value,
19
+ # [3] items.id AS item_id,
20
+ # [4] items.title as item_title,
21
+ # [5] items.is_main,
22
+ # [6] items.is_hit,
23
+ # [7] items.is_sale,
24
+ # [8] strsubcats.id AS strsubcat_id,
25
+ # [9] strsubcats.slug AS strsubcat_slug
26
+ # [10] vendors.id as vendor_id
27
+ # [11] vendors.title as vendor_title - дублирующий столбец: чтобы не совершать
28
+ # лишних запросов за vendor.title в методе hash_sql_make
29
+ # [12] items.full_desc
30
+ # [13] items.image
31
+ # [14] items.is_ask_price
32
+ # [15] `c80_yax_items`.`is_gift`,
33
+ # [16] `c80_yax_items`.`is_starting`,
34
+ # [17] `c80_yax_items`.`is_available`
35
+ # выбираем свойства предметов вместе с инфой о предметах, которым они принадлежат
36
+
37
+ # <editor-fold desc="# составляем и выполняем sql запрос">
38
+
39
+ # NOTE:: [columns] эти столбцы должны соответствовать (запрос при заполнении таблицы)
40
+
41
+ sql = "
42
+ SELECT
43
+ `c80_yax_item_props`.`prop_name_id`,
44
+ `c80_yax_prop_names`.`title` AS prop_name_title,
45
+ `c80_yax_item_props`.`value`,
46
+ `c80_yax_items`.`id` AS item_id,
47
+ `c80_yax_items`.`title` AS item_title,
48
+ `c80_yax_items`.`is_main`,
49
+ `c80_yax_items`.`is_hit`,
50
+ `c80_yax_items`.`is_sale`,
51
+ `c80_yax_strsubcats`.`id` AS strsubcat_id,
52
+ `c80_yax_strsubcats`.`slug` AS strsubcat_slug,
53
+ `c80_yax_vendors`.`id` AS vendor_id,
54
+ `c80_yax_vendors`.`title` AS vendor_title,
55
+ `c80_yax_items`.`full_desc`,
56
+ `c80_yax_items`.`image`,
57
+ `c80_yax_items`.`is_ask_price`,
58
+ `c80_yax_items`.`is_gift`,
59
+ `c80_yax_items`.`is_starting`,
60
+ `c80_yax_items`.`is_available`
61
+ FROM `c80_yax_items`
62
+ INNER JOIN `c80_yax_strsubcats` ON `c80_yax_strsubcats`.`id` = `c80_yax_items`.`strsubcat_id`
63
+ LEFT JOIN `c80_yax_item_props` ON `c80_yax_item_props`.`item_id` = `c80_yax_items`.`id`
64
+ LEFT JOIN `c80_yax_prop_names` ON `c80_yax_prop_names`.`id` = `c80_yax_item_props`.`prop_name_id`
65
+ LEFT JOIN `c80_yax_items_vendors` ON `c80_yax_items_vendors`.`item_id` = `c80_yax_items`.`id`
66
+ LEFT JOIN `c80_yax_vendors` ON `c80_yax_vendors`.`id` = `c80_yax_items_vendors`.`vendor_id`
67
+ WHERE (`c80_yax_strsubcats`.`id` = #{strsubcat_id})
68
+ "
69
+ records = ActiveRecord::Base.connection.execute(sql)
70
+ records
71
+ # </editor-fold>
72
+
73
+ # 1. заполняем хэш объектами для составления sql-команд INSERT
74
+ hash_sql = self.hash_sql_make(records, strsubcat_id)
75
+
76
+ Rails.logger.debug '[TRACE] <StrsubcatRuntimeTables.table_fill> Начинаем заполнять таблицу:'
77
+ self.hash_sql_execute(hash_sql)
78
+ Rails.logger.debug '[TRACE] <StrsubcatRuntimeTables.table_fill> END'
79
+
80
+ end
81
+
82
+ =begin
83
+ # выдать список вещей из указанной подкатегории (возможно, применяя фильтры)
84
+ def strh_items_filter(strsubcat_id, page, per_page, sorting_type, filter_params = {})
85
+
86
+ # Rails.logger.debug "page = #{page}"
87
+ # Rails.logger.debug "per_page = #{per_page}"
88
+
89
+ table_name = "strcat_#{strsubcat_id}_items"
90
+ Rails.logger.debug "[TRACE] <strh_filter_items> START: #{table_name}, sorting_type = #{sorting_type}, filter_params = #{filter_params.to_json}"
91
+
92
+ if ActiveRecord::Base.connection.table_exists?(table_name)
93
+
94
+ ob = compose_sql_order_by(strsubcat_id,sorting_type)
95
+ w = compose_where_sql(filter_params, table_name)
96
+ sql = "SELECT * FROM #{table_name}#{w}#{ob}"
97
+
98
+ # SELECT * FROM strcat_1_items
99
+ # WHERE
100
+ # strcat_1_items.prop_1 = '5 кг'
101
+ # AND
102
+ # strcat_1_items.prop_3 = '1450 кг/м3';
103
+
104
+ items = Item.paginate_by_sql(sql, :page => page, :per_page => per_page)
105
+
106
+ Rails.logger.debug "[TRACE] <strh_filter_items> END"
107
+ else
108
+ # сюда попадаем в исключительной ситуации - ошибка т.е.
109
+ Rails.logger.debug "[ERROR] <strh_filter_items> Нет таблицы с именем #{table_name}"
110
+ items = Item.all.paginate(:page => 1, :per_page => 0)
111
+ end
112
+ items
113
+
114
+ end
115
+ =end
116
+
117
+ =begin
118
+ # от метода ожидается результат: хэш вида {"3"=>["900 кг/м3", "1450 кг/м3"], "5"=>["300 мм", "2300 x 1250 x 900"], "9"=>["20 %", "13%", "12%"]}
119
+ def strh_collect_allowed_vals(strsubcat_id,filter_params={})
120
+ # filter_params = {"1"=>"5 кг", "3"=>"-1", "5"=>"-1", "9"=>"-1"}
121
+
122
+ table_name = "strcat_#{strsubcat_id}_items"
123
+ if ActiveRecord::Base.connection.table_exists?(table_name)
124
+
125
+ s = 'SET SESSION group_concat_max_len = 102400000'
126
+ ActiveRecord::Base.connection.execute(s)
127
+
128
+ w = compose_where_sql(filter_params, table_name)
129
+ g = compose_group_concat_sql(filter_params)
130
+ sql = "SELECT id#{g} FROM #{table_name}#{w}"
131
+ records_array = ActiveRecord::Base.connection.exec_query(sql)
132
+ hsh = records_array.to_hash
133
+ # Rails.logger.debug "<strh_collect_allowed_vals> Промежуточный hash: #{hsh}"
134
+
135
+ # Rails.logger.debug "strh_collect_allowed_vals:: #{hsh}"
136
+ # [{"id"=>3, "3"=>"95 г/м3,1450 кг/м3", "5"=>"2500 x 1200 x 800,2500 x 1200 x 800", "9"=>"0.51 %,0.51 %"}]
137
+
138
+ # посчитаем, сколько фильтров используется
139
+ # если используется один фильтр - зафиксируе его key
140
+ # чтобы для него собрать все возможные значения
141
+ # чтобы в <select>`е были доступны все <options>
142
+ # NOTE:: этот метод вообще работает?
143
+ prop_id = is_only_one_filter_use(filter_params={})
144
+ unless prop_id == -1
145
+ # Rails.logger.debug "<strh_collect_allowed_vals> Фильтруем только по одному признаку."
146
+ hsh[0][prop_id.to_s] = strh_collect_all_vals(prop_id, table_name)
147
+ end
148
+
149
+ res = {}
150
+ hsh[0].each_key do |key|
151
+ unless key["id"]
152
+ res[key] = hsh[0][key].split('----') if hsh[0][key].present?
153
+ end
154
+ end
155
+ Rails.logger.debug "[TRACE] <strh_collect_allowed_vals> Собрали, результат: #{res}"
156
+ # {"3"=>["900 кг/м3", "1450 кг/м3", "1450 кг/м3"], "5"=>["300 мм", "2300 x 1250 x 900", "2300 x 1250 x 900"], "9"=>["20 %", "13%", "12%"]}
157
+ else
158
+ res = {}
159
+ end
160
+
161
+ res
162
+
163
+ end
164
+ =end
165
+
166
+ =begin
167
+ # Для подкатегории strsubcat_id соберёт список всех характеристик,
168
+ # по которым строится фильтр панель.
169
+ #
170
+ # Например: на вход подаётся `filter_params = {"36"=>"Идеальный камень"}`,
171
+ # результат будет: {"36"=>"Идеальный камень", "29"=>"-1", "32"=>"-1"}
172
+ # и результат будет означать, что данная подкатегория может фильтроваться
173
+ # по 3-ём характеристикам, и одна из них в данный момент выставлена в селектах.
174
+ #
175
+ # 20170616
176
+ # NOTE:: как stroy_mat_render_helper::sth_render_prop_names
177
+ def strh_collect_all_filter_vals(strsubcat_id, filter_params={})
178
+ Rails.logger.debug "[TRACE] <strh_collect_all_filter_vals!> before: #{filter_params}"
179
+
180
+ result = filter_params.clone
181
+ strsubcat = Strsubcat.find(strsubcat_id)
182
+
183
+ # собираем массив всех имён свойств подкатегории:
184
+ # если такое свойство уже есть в filter_params - пропускаем
185
+ # если свойство исключено из фильтрации - пропускаем
186
+ ar_prop_names = strsubcat.prop_names
187
+ ar_prop_names.each do |prop_name|
188
+ pid = prop_name.id.to_s
189
+ unless result[pid].present?
190
+ result[pid] = '-1' unless prop_name.is_excluded_from_filtering
191
+ end
192
+ end
193
+
194
+ Rails.logger.debug "[TRACE] <strh_collect_all_filter_vals!> after: #{filter_params}"
195
+ result
196
+
197
+ end
198
+ =end
199
+
200
+ # создаёт таблицу под все вещи подкатегории, если такой таблицы нету в базе
201
+ def self.table_check_and_build(strsubcat) # strh_table_check_and_build
202
+
203
+ # по-умолчанию в результате исполнения метода - таблицу создавать не надо
204
+ # noinspection RubyUnusedLocalVariable
205
+ mark_create_table = false
206
+
207
+ runtime_table_name = "c80_yax_strcat_#{strsubcat.id}_items"
208
+
209
+ # <editor-fold desc="# Сначала составим список айдишников всех свойств, присущих данной категории">
210
+ # выбрать из базы айдишники всех свойств, присущих данной категории
211
+ # по сути дела, тоже самое, что и strsubcat.prop_names
212
+ sql = "
213
+ SELECT `c80_yax_prop_names`.`id`
214
+ FROM `c80_yax_prop_names`
215
+ INNER JOIN `c80_yax_prop_names_strsubcats` ON `c80_yax_prop_names`.`id` = `c80_yax_prop_names_strsubcats`.`prop_name_id`
216
+ WHERE `c80_yax_prop_names_strsubcats`.`strsubcat_id` = #{strsubcat.id}
217
+ "
218
+ records = ActiveRecord::Base.connection.execute(sql)
219
+
220
+ propnames_ids = []
221
+ records.each do |r|
222
+ propnames_ids << r[0].to_i
223
+ end
224
+ # </editor-fold>
225
+
226
+ # Теперь определимся, нужно ли дропнуть и создать таблицу
227
+ if ActiveRecord::Base.connection.table_exists? runtime_table_name
228
+ Rails.logger.debug "[TRACE] <StrsubcatRuntimeTables.table_check_and_build> Таблица уже существует: #{runtime_table_name}"
229
+
230
+ # <editor-fold desc="# совпадают ли столбцы runtime таблицы и свойства?">
231
+ # проверим, совпадают ли столбцы свойств в runtime таблице со списком свойств, присущих данной категории:
232
+ # если какого-то свойства нет в столбцах - дропнем таблицу и создадим её заново
233
+ # если есть лишний столбец в таблице - дропнем таблицу и создадим её заново
234
+ Rails.logger.debug '[TRACE] <StrsubcatRuntimeTables.table_check_and_build> Проверим соответствие столбцов свойствам.'
235
+
236
+ # получим список столбцов и извлечём из него айдишники свойств в массив +actual_props_ids+
237
+ sql_describe = "DESCRIBE #{runtime_table_name}"
238
+ records = ActiveRecord::Base.connection.execute(sql_describe)
239
+ actual_props_ids = []
240
+ records.each do |row|
241
+ actual_props_ids << row[0][/\d+/].to_i if row[0]['prop_']
242
+ end
243
+
244
+ mark_create_table = actual_props_ids.sort != propnames_ids.sort
245
+ Rails.logger.debug "[TRACE] <StrsubcatRuntimeTables.table_check_and_build> Сравним propnames_ids = #{propnames_ids} и actual_props_ids = #{actual_props_ids}."
246
+ Rails.logger.debug "[TRACE] <StrsubcatRuntimeTables.table_check_and_build> mark_create_table = #{mark_create_table}."
247
+ # </editor-fold>
248
+
249
+ # если не совпадают - дропнем таблицу
250
+ if mark_create_table
251
+ self.table_drop(strsubcat)
252
+ end
253
+
254
+ else
255
+ Rails.logger.debug "[TRACE] <check_and_build_table> Таблица не существует, создаём: #{runtime_table_name}"
256
+ mark_create_table = true
257
+ end
258
+
259
+ # Если таблицу надо создать - создаём
260
+ if mark_create_table
261
+ self.table_create(runtime_table_name, propnames_ids)
262
+ end
263
+
264
+ end
265
+
266
+ # враппер метода ActiveRecord::Migration.create_table
267
+ # создаёт таблицу с именем strcat_#{strsubcat_id}_items
268
+ # со столбцами, описанными в массиве props_names_list (имя столбца вида prop_#{item})
269
+ def self.table_create(runtime_table_name, propnames_ids) # strh_table_create
270
+ Rails.logger.debug "[TRACE] <StrsubcatRuntimeTables.table_create> BEGIN. propnames_ids = #{propnames_ids}"
271
+
272
+ ActiveRecord::Migration.create_table(runtime_table_name, :options => 'COLLATE=utf8_unicode_ci') do |t|
273
+
274
+ # NOTE:: [columns] эти столбцы должны соответствовать (создание новой таблицы)
275
+
276
+ t.integer :item_id
277
+ t.string :item_title
278
+ t.boolean :is_main
279
+ t.boolean :is_hit
280
+ t.boolean :is_sale
281
+ t.integer :strsubcat_id
282
+ t.string :strsubcat_slug
283
+ t.integer :vendor_id
284
+ t.text :full_desc
285
+ t.string :image
286
+ t.boolean :is_ask_price
287
+ t.boolean :is_gift
288
+ t.boolean :is_starting
289
+ t.boolean :is_available
290
+
291
+ t.index :item_id, unique: true
292
+
293
+ # т.к. сортировка средствами SQL (ORDER BY) нам
294
+ # нужна только для цен, то только столбцы для
295
+ # цен делаем числами. Остальное - храним, как строки.
296
+ propnames_ids.each do |prop_name_id|
297
+ is_decimal_column = C80Yax::PropName.find(prop_name_id).is_normal_price
298
+ if is_decimal_column
299
+ t.decimal "prop_#{prop_name_id}", :precision => 8, :scale => 2
300
+ else
301
+ t.string "prop_#{prop_name_id}"
302
+ end
303
+
304
+ end
305
+
306
+ end
307
+
308
+ Rails.logger.debug '[TRACE] <StrsubcatRuntimeTables.table_create> END'
309
+
310
+ end
311
+
312
+ def self.table_drop(strsubcat) # strh_table_drop
313
+ runtime_table_name = "c80_yax_strcat_#{strsubcat.id}_items"
314
+ if ActiveRecord::Base.connection.table_exists?(runtime_table_name)
315
+ Rails.logger.debug "[TRACE] <StrsubcatRuntimeTables.table_drop> Удаляем таблицу: table_name = #{runtime_table_name}"
316
+ ActiveRecord::Migration.drop_table(runtime_table_name)
317
+ Rails.logger.debug '[TRACE] <StrsubcatRuntimeTables.table_drop> END'
318
+ end
319
+ end
320
+
321
+ # удаляем из таблицы item_props те строки, у которых strsubcat_id == ID
322
+ # и чьё prop_name_id входит в список свойств LIST
323
+ # вызывается только в методе StrsubcatSweeper.after_update
324
+ def self.check_and_clean_item_props(strsubcat) # strh_check_and_clean_item_props
325
+ list = strsubcat.get_list_removed_props
326
+
327
+ if list.count > 0
328
+ Rails.logger.debug '[TRACE] <StrsubcatRuntimeTables.check_and_clean_item_props> Чистим item_props.'
329
+ # 1.1. Сначала составим список свойств, которые надо удалить.
330
+
331
+ sql = "
332
+ SELECT
333
+ `c80_yax_item_props`.`id`,
334
+ `c80_yax_item_props`.`prop_name_id`,
335
+ `c80_yax_prop_names`.`title` AS prop_name_title,
336
+ `c80_yax_item_props`.`value`,
337
+ `c80_yax_items`.`id` AS item_id,
338
+ `c80_yax_items`.`title` as item_title,
339
+ `c80_yax_items`.`is_main`,
340
+ `c80_yax_items`.`is_hit`,
341
+ `c80_yax_items`.`is_sale`,
342
+ `c80_yax_strsubcats`.`id` AS strsubcat_id,
343
+ `c80_yax_strsubcats`.`slug` AS strsubcat_slug
344
+ FROM `c80_yax_items`
345
+ INNER JOIN `c80_yax_strsubcats` ON `c80_yax_strsubcats`.`id` = `c80_yax_items`.`strsubcat_id`
346
+ LEFT JOIN `c80_yax_item_props` ON `c80_yax_item_props`.`item_id` = `c80_yax_items`.`id`
347
+ LEFT JOIN `c80_yax_prop_names` ON `c80_yax_prop_names`.`id` = `c80_yax_item_props`.`prop_name_id`
348
+ WHERE `c80_yax_strsubcats`.`id` = #{ strsubcat.id }
349
+ AND `c80_yax_prop_name_id` IN (#{ list.join(',')})
350
+ "
351
+
352
+ records = ActiveRecord::Base.connection.execute(sql)
353
+
354
+ # 1.2. Составим список айдишников свойств для удаления
355
+ item_props_ids = []
356
+ records.each do |row|
357
+ item_props_ids << row[0]
358
+ end
359
+
360
+ # 2. Теперь на основе списка свойств, которые надо удалить, составим запрос, который удалит эти свойства.
361
+ if item_props_ids.count > 0
362
+ sql = "
363
+ DELETE FROM `c80_yax_item_props`
364
+ WHERE `id` IN (#{ item_props_ids.join(',') })
365
+ "
366
+
367
+ ActiveRecord::Base.connection.execute(sql)
368
+ end
369
+
370
+ Rails.logger.debug '[TRACE] <StrsubcatRuntimeTables.check_and_clean_item_props> END'
371
+ end
372
+
373
+ end
374
+
375
+ # из таблицы типа strcat_111_items удалить строку, описывающую вещь item_id
376
+ def self.item_drop(strsubcat_id, item_id) # strh_item_drop
377
+ runtime_table_name = "c80_yax_strcat_#{strsubcat_id}_items"
378
+ Rails.logger.debug "[TRACE] <StrsubcatRuntimeTables.item_drop> Удаляем вещь id = #{item_id} из таблицы `#{runtime_table_name}`."
379
+ if ActiveRecord::Base.connection.table_exists?(runtime_table_name)
380
+ sql = "
381
+ DELETE FROM #{runtime_table_name}
382
+ WHERE item_id = #{item_id}
383
+ "
384
+
385
+ ActiveRecord::Base.connection.execute(sql)
386
+ end
387
+ end
388
+
389
+ # в таблице типа strcat_111_items обновить поля строки, описывающую вещь item_id
390
+ def self.item_update(strsubcat_id,item_id) # strh_item_update
391
+ runtime_table_name = "c80_yax_strcat_#{strsubcat_id}_items"
392
+ Rails.logger.debug "[TRACE] <StrsubcatRuntimeTables.item_update> В таблице `#{runtime_table_name}` обновим данные о товаре id = #{item_id}."
393
+
394
+ # <editor-fold desc="# сначала соберём все свойства вещи">
395
+ # NOTE:: [columns] эти столбцы должны соответствовать (запрос при обновлении предмета)
396
+ sql = "
397
+ SELECT
398
+ `c80_yax_item_props`.`prop_name_id`,
399
+ `c80_yax_prop_names`.`title` AS prop_name_title,
400
+ `c80_yax_item_props`.`value`,
401
+ `c80_yax_items`.`id` AS item_id,
402
+ `c80_yax_items`.`title` as item_title,
403
+ `c80_yax_items`.`is_main`,
404
+ `c80_yax_items`.`is_hit`,
405
+ `c80_yax_items`.`is_sale`,
406
+ `c80_yax_strsubcats`.`id` AS strsubcat_id,
407
+ `c80_yax_strsubcats`.`slug` AS strsubcat_slug,
408
+ `c80_yax_vendors`.`id` as vendor_id,
409
+ `c80_yax_vendors`.`title` as vendor_title,
410
+ `c80_yax_items`.`full_desc`,
411
+ `c80_yax_items`.`image`,
412
+ `c80_yax_items`.`is_ask_price`,
413
+ `c80_yax_items`.`is_gift`,
414
+ `c80_yax_items`.`is_starting`,
415
+ `c80_yax_items`.`is_available`
416
+ FROM `c80_yax_items`
417
+ INNER JOIN `c80_yax_strsubcats` ON `c80_yax_strsubcats`.`id` = `c80_yax_items`.`strsubcat_id`
418
+ LEFT JOIN `c80_yax_item_props` ON `c80_yax_item_props`.`item_id` = `c80_yax_items`.`id`
419
+ LEFT JOIN `c80_yax_prop_names` ON `c80_yax_prop_names`.`id` = `c80_yax_item_props`.`prop_name_id`
420
+ LEFT JOIN `c80_yax_items_vendors` ON `c80_yax_items_vendors`.`item_id` = `c80_yax_items`.`id`
421
+ LEFT JOIN `c80_yax_vendors` ON `c80_yax_vendors`.`id` = `c80_yax_items_vendors`.`vendor_id`
422
+ WHERE (`c80_yax_strsubcats`.`id` = #{strsubcat_id})
423
+ AND `c80_yax_items`.`id` = #{item_id};
424
+ "
425
+ records = ActiveRecord::Base.connection.execute(sql)
426
+ # </editor-fold>
427
+
428
+ # составим SQL команду
429
+ hash_sql = self.hash_sql_make(records, strsubcat_id)
430
+
431
+ #-> удалим старую строку
432
+ sql = "DELETE FROM `#{runtime_table_name}` WHERE item_id = #{item_id}"
433
+ ActiveRecord::Base.connection.execute(sql)
434
+
435
+ #-> выполним SQL команду : вставим строку с обновлёнными значениями
436
+ self.hash_sql_execute(hash_sql)
437
+
438
+ Rails.logger.debug '[TRACE] <StrsubcatRuntimeTables.strh_item_update> END'
439
+ end
440
+
441
+ =begin
442
+ # выдать строку, описывающую товар с id=item_id из подкатегории id=strsubcat_id
443
+ # {"id"=>84, "item_id"=>1, "item_title"=>"Кирпич облицовочный Labassa стандарт качества Qbricks", "is_main"=>0, "is_hit"=>0, "is_sale"=>1, "strsubcat_slug"=>"kirpich", "prop_18"=>"13,85", "prop_19"=>"15", "prop_20"=>"16", "prop_21"=>"18", "prop_23"=>"250 x 85 x 65 мм", "prop_24"=>"Румыния", "prop_25"=>"150", "prop_26"=>"0,60", "prop_27"=>"F300", "prop_28"=>"12,8", "prop_29"=>"красный", "prop_30"=>"пустотелый", "prop_31"=>"пластичное формование", "prop_32"=>"гладкая", "prop_33"=>"1,5", "prop_34"=>"458", "prop_35"=>"лицевой, фасадный", "prop_36"=>"Ibstock", "prop_37"=>"GE-02 A", "prop_38"=>"BS"}
444
+ def strh_item_get(strsubcat_id,item_id)
445
+ # http://stackoverflow.com/questions/5760100/why-does-rails-3-with-mysql2-gem-activerecordbase-connection-executesql-retu
446
+ sql = "SELECT * FROM strcat_#{strsubcat_id}_items WHERE item_id = #{item_id}"
447
+ rows = ActiveRecord::Base.connection.execute(sql)
448
+ # т.к. результат может быть только в виде одного объекта - вернём первую попавшуюся строку
449
+ rows.each(:as => :hash) do |row|
450
+ # Rails.logger.debug "#{row['item_title']}"
451
+ return row
452
+ end
453
+ end
454
+ =end
455
+
456
+ private
457
+
458
+ =begin
459
+ def compose_where_sql(filter_params={},table_name)
460
+ result = []
461
+ a = filter_params
462
+ a.each_key do |key|
463
+ result << "#{table_name}.prop_#{key} = '#{a[key]}'" unless a[key] == '-1' # strcat_1_items.prop_1 = '5 кг'
464
+ end
465
+ if result.count > 0
466
+ " WHERE #{result.join(' AND ')}"
467
+ else
468
+ ""
469
+ end
470
+ end
471
+ =end
472
+
473
+ =begin
474
+ # от метода ожидается результат: строка вида ", GROUP_CONCAT(prop_3 SEPARATOR '----') all_prop_3, GROUP_CONCAT(prop_5 SEPARATOR '----') all_prop_5"
475
+ def compose_group_concat_sql(filter_params={})
476
+ # filter_params = {"1"=>"5 кг", "3"=>"-1", "5"=>"-1", "9"=>"-1"}
477
+
478
+ res = []
479
+ filter_params.each_key do |key|
480
+ res << "GROUP_CONCAT(prop_#{key} SEPARATOR '----') `#{key}`" # if filter_params[key].to_s["-1"]
481
+ end
482
+ ", #{res.join(", ")}"
483
+
484
+ end
485
+ =end
486
+
487
+ # NOTE:: этот метод вообще работает?
488
+ def is_only_one_filter_use(filter_params={})
489
+
490
+ c = filter_params.count
491
+ key_filter_used = -1
492
+ filter_params.each_key do |key|
493
+ if filter_params[key].to_s["-1"]
494
+ c -= 1
495
+ else
496
+ key_filter_used = key
497
+ end
498
+ end
499
+
500
+ if c == 1
501
+ only_one_filter_used = true
502
+ else
503
+ only_one_filter_used = false
504
+ key_filter_used = -1
505
+ end
506
+
507
+ Rails.logger.debug "[TRACE] <StrItemsHelper.is_only_one_filter_use> filters in use = #{c}; only_one_filter_used = #{only_one_filter_used}, key_filter_used = #{key_filter_used}"
508
+ key_filter_used
509
+
510
+ end
511
+
512
+ =begin
513
+ # собираем все доступные значения для селекта
514
+ def strh_collect_all_vals(prop_id,table_name)
515
+ # SELECT
516
+ # id,
517
+ # GROUP_CONCAT(prop_3 SEPARATOR '----') all_values_3
518
+ # FROM strcat_1_items;
519
+
520
+ s = 'SET SESSION group_concat_max_len = 102400000'
521
+ ActiveRecord::Base.connection.execute(s)
522
+
523
+ sql = "SELECT id, GROUP_CONCAT(prop_#{prop_id} SEPARATOR '----') all_values_#{prop_id} FROM #{table_name}"
524
+ records_array = ActiveRecord::Base.connection.exec_query(sql)
525
+ hsh = records_array.to_hash
526
+ # [{"id"=>1, "3"=>"95 г/м3,1450 кг/м3"}]
527
+
528
+ res = {}
529
+ hsh[0].each_key do |key|
530
+ unless key["id"]
531
+ res = hsh[0][key]
532
+ break
533
+ end
534
+ end
535
+
536
+ Rails.logger.debug "<strh_collect_all_vals> Cобрали все доступные значения для селекта id=#{prop_id}: res = #{res}"
537
+ res
538
+
539
+ end
540
+ =end
541
+
542
+ def self.hash_sql_make(records, strsubcat_id)
543
+ Rails.logger.debug "[TRACE] <StrsubcatRuntimeTables.hash_sql_make> Составляем SQL для обновления/создания записи в runtime-таблице `c80_yax_strcat_#{strsubcat_id}_items`. records.count = #{records.count}."
544
+
545
+ hash_sql = {}
546
+
547
+ records.each do |item_prop|
548
+
549
+ prop_name_id = item_prop[0]
550
+ prop_value = item_prop[2]
551
+ item_id = item_prop[3]
552
+ is_ask_price = item_prop[14]
553
+
554
+
555
+ # <editor-fold desc="# производим магические манипуляции с Производителем">
556
+ # если это свойство "бренд" -
557
+ # то игнорируем значение, которое лежит в таблице itep_props
558
+ vendor_id = item_prop[10]
559
+ vendor_title = item_prop[11]
560
+ if prop_name_id == 36 # NOTE-HARD-CODE-PROP-NAME
561
+ prop_value = vendor_title
562
+ if prop_value.blank?
563
+ prop_value = 'Не указан'
564
+ end
565
+ end
566
+
567
+ # корректируем значение
568
+ unless vendor_id.present?
569
+ vendor_id = -1
570
+ end
571
+ # </editor-fold>
572
+
573
+ # <editor-fold desc="# манипулируем с is_ask_price">
574
+ if is_ask_price.present?
575
+ if is_price
576
+ # если у товара is_ask_price = true, то игнорируем значение, которое лежит в таблице
577
+ # item_props и в prop_value помещаем максимально возможное значение, чтобы товар, при сортировке
578
+ # по цене, уходил в самый конец списка
579
+ # 20170402: также опытным путём выяснилось, что надо также обновлять значение
580
+ # в таблице items_props
581
+ if is_ask_price.to_i == 1
582
+ Rails.logger.debug '[TRACE] <StrsubcatRuntimeTables.hash_sql_make> is_ask_price=TRUE.'
583
+ prop_value = 999999
584
+ # и обновляем значение в таблице items_props
585
+ item_prop_price = C80Yax::ItemProp.where(:item_id => item_id).where(:prop_name_id => prop_name_id)
586
+ if item_prop_price.count > 0
587
+ item_prop_price.first.update_column(:value, 999999)
588
+ end
589
+ end
590
+ end
591
+ else
592
+ # защищаемся от ошибки "Mysql2::Error: Incorrect integer value: '' for column 'is_ask_price'"
593
+ is_ask_price = 0
594
+ end
595
+ # </editor-fold>
596
+
597
+ # кэшируем первый раз
598
+ unless hash_sql[item_id].present?
599
+ # Rails.logger.debug "\t new hash"
600
+ hash_sql[item_id] = {
601
+ prop_names_ids: %w'item_id item_title is_main is_hit is_sale strsubcat_id strsubcat_slug vendor_id full_desc image is_ask_price is_gift is_starting is_available',
602
+ values: [item_id,item_prop[4],item_prop[5],item_prop[6],item_prop[7],item_prop[8],item_prop[9],vendor_id,item_prop[12],item_prop[13], is_ask_price, item_prop[15], item_prop[16], item_prop[17]],
603
+ sql: "INSERT INTO `c80_yax_strcat_#{strsubcat_id}_items` ({props}) VALUES ({values})"
604
+ }
605
+ end
606
+
607
+ # byebug
608
+ Rails.logger.debug "[TRACE] <StrsubcatRuntimeTables.hash_sql_make> prop_name_id: #{prop_name_id}, prop_value: #{prop_value}."
609
+
610
+ # добавляем в кэш
611
+ hash_sql[item_id][:prop_names_ids] << "prop_#{prop_name_id}"
612
+ hash_sql[item_id][:values] << prop_value
613
+
614
+ end
615
+
616
+ # 2. обходим этот хэш, для каждого объекта формируем sql-команду на основе данных объекта хэша
617
+ hash_sql.each_key do |key|
618
+ obj = hash_sql[key]
619
+ p = "`#{obj[:prop_names_ids].join("`,`")}`"
620
+ v = "'#{obj[:values].join("','")}'"
621
+ obj[:sql] = obj[:sql].gsub(/\{props\}/,p)
622
+ obj[:sql] = obj[:sql].gsub(/\{values\}/,v)
623
+ end
624
+ hash_sql
625
+
626
+ end
627
+
628
+ def self.hash_sql_execute(hash_sql)
629
+
630
+ # INSERT INTO Table1
631
+ # (`id`, `name`)
632
+ # VALUES
633
+ # (1, 'foo'),
634
+ # (1, 'bar'),
635
+ # (1, 'foobar'),
636
+ # (2, 'foo'),
637
+ # (2, 'bar'),
638
+ # (2, 'foobar')
639
+ #;
640
+ hash_sql.each_key do |key|
641
+ sql = hash_sql[key][:sql]
642
+ # Rails.logger.debug sql
643
+ begin
644
+ ActiveRecord::Base.connection.execute(sql)
645
+ rescue Exception => e
646
+ Rails.logger.debug "[TRACE] <StrsubcatRuntimeTables.hash_sql_execute> #{e}"
647
+ end
648
+ end
649
+ end
650
+
651
+ =begin
652
+ # составить sql строку, которая прицепится к запросу выборки вещей
653
+ # и будет содержать комаду вида:
654
+ # "отсортировать по 'цене 1' по возрастанию или по убыванию"
655
+ # Если у подкатегории нет "цены 1" - вернётся пустая строка
656
+ def compose_sql_order_by(strsubcat_id,sorting_type)
657
+ result = ""
658
+ price_prop_id = PriceProp.gget_sort_pprop_for_strsubcat(strsubcat_id)
659
+ if price_prop_id != ""
660
+ asc_or_desc = SortingType.where(:sort_type => sorting_type).first.sql
661
+ result = " ORDER BY prop_#{price_prop_id} #{asc_or_desc}"
662
+ end
663
+ Rails.logger.debug "<order_by_sql_make> Сортировка по 'цене 1': '#{result}'"
664
+ result
665
+ end
666
+ =end
667
+
668
+ end
@@ -1,3 +1,3 @@
1
1
  module C80Yax
2
- VERSION = '0.1.0.1'
2
+ VERSION = '0.1.0.2'
3
3
  end
data/lib/c80_yax.rb CHANGED
@@ -1,5 +1,7 @@
1
- require "c80_yax/version"
2
- require "c80_yax/engine"
1
+ require 'c80_yax/version'
2
+ require 'c80_yax/engine'
3
+ require 'c80_yax/strsubcat_runtime_tables'
4
+ require 'rails-observers'
3
5
 
4
6
  module C80Yax
5
7
  def self.table_name_prefix