pg_rails 7.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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +73 -0
  4. data/Rakefile +36 -0
  5. data/app/assets/javascripts/pg_rails/asociacion_creable.js +85 -0
  6. data/app/assets/javascripts/pg_rails/best_in_place_datepicker.js +58 -0
  7. data/app/assets/javascripts/pg_rails/librerias.js +13 -0
  8. data/app/assets/javascripts/pg_rails/librerias_b3.js +14 -0
  9. data/app/assets/javascripts/pg_rails/validaciones.js +44 -0
  10. data/app/assets/javascripts/pg_rails.js +318 -0
  11. data/app/assets/stylesheets/pg_rails/librerias.scss +5 -0
  12. data/app/assets/stylesheets/pg_rails/pg_chosen.scss +29 -0
  13. data/app/assets/stylesheets/pg_rails/pg_rails.scss +199 -0
  14. data/app/assets/stylesheets/pg_rails_b3.scss +10 -0
  15. data/app/assets/stylesheets/pg_rails_b4.scss +12 -0
  16. data/app/assets/stylesheets/pg_rails_b5.scss +1 -0
  17. data/app/controllers/pg_rails/application_controller.rb +316 -0
  18. data/app/controllers/pg_rails/editar_en_lugar_controller.rb +24 -0
  19. data/app/decorators/pg_rails/base_decorator.rb +120 -0
  20. data/app/helpers/pg_rails/editar_en_lugar_helper.rb +106 -0
  21. data/app/helpers/pg_rails/form_helper.rb +25 -0
  22. data/app/helpers/pg_rails/postgres_helper.rb +15 -0
  23. data/app/helpers/pg_rails/print_helper.rb +176 -0
  24. data/app/inputs/pg_rails/asociacion_creable_input.rb +72 -0
  25. data/app/inputs/pg_rails/fecha_input.rb +20 -0
  26. data/app/inputs/pg_rails/selects_dependientes_input.rb +9 -0
  27. data/app/lib/pg_form_builder.rb +31 -0
  28. data/app/lib/pg_rails/filtros_builder.rb +338 -0
  29. data/app/models/pg_rails/application_record.rb +51 -0
  30. data/app/policies/pg_rails/application_policy.rb +104 -0
  31. data/app/views/application/_abrir_modal.js.erb +14 -0
  32. data/app/views/application/_actualizar_smart_listing.html.slim +3 -0
  33. data/app/views/application/_cerrar_modal.js.erb +8 -0
  34. data/app/views/application/_modal_ajax_form.js.erb +7 -0
  35. data/config/brakeman.ignore +42 -0
  36. data/config/locales/es.yml +17 -0
  37. data/config/routes.rb +3 -0
  38. data/config/spring.rb +1 -0
  39. data/lib/pg_rails/configuracion.rb +24 -0
  40. data/lib/pg_rails/core_ext.rb +17 -0
  41. data/lib/pg_rails/engine.rb +42 -0
  42. data/lib/pg_rails/simple_form/initializer.rb +583 -0
  43. data/lib/pg_rails/utils/logueador.rb +39 -0
  44. data/lib/pg_rails/version.rb +5 -0
  45. data/lib/pg_rails.rb +23 -0
  46. data/lib/tasks/auto_anotar_modelos.rake +34 -0
  47. data/lib/tasks/pg_rails_tasks.rake +5 -0
  48. metadata +89 -0
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgRails
4
+ module EditarEnLugarHelper
5
+ def editar_en_lugar(objeto, atributo, tipo = :input, url = nil, collection = nil)
6
+ url = pg_rails.editar_en_lugar_path(objeto) if url.nil?
7
+ if tipo == :checkbox
8
+ best_in_place objeto, atributo, url: url, as: tipo, collection: %w[No Si],
9
+ param: objeto.model_name.name
10
+ elsif tipo == :date
11
+ best_in_place objeto, atributo, url: url, as: tipo, display_with: lambda { |v|
12
+ dmy(v)
13
+ }, param: objeto.model_name.name
14
+ # best_in_place objeto, atributo, url: editar_en_lugarurl(objeto), as: tipo, display_with: lambda { |v| dmy(v) }, class: 'datefield'
15
+ elsif tipo == :textarea
16
+ funcion = lambda do |valor|
17
+ return unless valor.present?
18
+
19
+ valor.gsub!("\r\n", '<br>')
20
+ valor.gsub!("\n", '<br>')
21
+ valor.html_safe
22
+ end
23
+ best_in_place objeto, atributo, url: url, as: tipo, display_with: funcion,
24
+ param: objeto.model_name.name
25
+ elsif tipo == :select && collection.present?
26
+ best_in_place objeto, atributo, url: url, as: tipo, collection: collection,
27
+ param: objeto.model_name.name, value: objeto.send(atributo), inner_class: 'form-control'
28
+ else
29
+ best_in_place objeto, atributo, url: url, as: tipo, param: objeto.model_name.name
30
+ end
31
+ end
32
+
33
+ # Versión mejorada de editar_en_lugar, pero le pongo v2 por retrocompatibilidad
34
+ # La diferencia es que recibe un hash "options" y se le pueden agregar cualquiera de las options
35
+ # que admite best_in_place
36
+ def editar_en_lugar_v2(objeto, atributo, tipo = :input, options = {})
37
+ options[:url] = pg_rails.editar_en_lugar_path(objeto) if options[:url].nil?
38
+ options[:as] = tipo
39
+ options[:param] = objeto.model_name.name
40
+ options[:inner_class] = 'form-control' if options[:inner_class].nil?
41
+ options[:class] = 'editar_en_lugar_v2'
42
+ options[:html_attrs] = { autocomplete: :off }
43
+ # url = pg_rails.editar_en_lugar_path(objeto) if url.nil?
44
+ if tipo == :checkbox
45
+ options[:collection] = %w[No Si]
46
+
47
+ elsif tipo == :date
48
+ options[:display_with] = ->(v) { dmy(v) } if options[:display_with].nil?
49
+
50
+ elsif tipo == :textarea
51
+ funcion = lambda do |valor|
52
+ return unless valor.present?
53
+
54
+ valor.gsub!("\r\n", '<br>')
55
+ valor.gsub!("\n", '<br>')
56
+ valor.html_safe
57
+ end
58
+ options[:display_with] = funcion if options[:display_with].nil?
59
+
60
+ elsif tipo == :select && options[:collection].present?
61
+ options[:value] = objeto.send(atributo)
62
+ end
63
+
64
+ best_in_place objeto, atributo, options
65
+ end
66
+
67
+ # TODO: mover a otro helper
68
+ def encabezado(campo, options = {})
69
+ clase = (options[:clase] || @clase_modelo)
70
+ if options[:ordenable]
71
+ field = controller.instance_variable_get(:"@field")
72
+ direction = controller.instance_variable_get(:"@direction")
73
+ uri = URI.parse(request.url)
74
+ if uri.query.present?
75
+ cgi = CGI.parse(uri.query)
76
+ else
77
+ cgi = {}
78
+ end
79
+ cgi["order_by"] = campo
80
+ cgi["order_direction"] =
81
+ if field.to_s == campo.to_s && direction.to_s == 'asc'
82
+ 'desc'
83
+ else
84
+ 'asc'
85
+ end
86
+
87
+ if field.to_s == campo.to_s
88
+ symbol =
89
+ if direction.to_s == 'asc'
90
+ '<i class="bi bi-sort-down-alt" />'
91
+ elsif direction.to_s == 'desc'
92
+ '<i class="bi bi-sort-up" />'
93
+ end
94
+ else
95
+ symbol = ''
96
+ end
97
+
98
+ uri.query = cgi.map {|a,b| [a, (b.length == 1 ? b.first : b)]}.to_h.to_query
99
+
100
+ link_to(clase.human_attribute_name(campo), uri.to_s) + " #{symbol}".html_safe
101
+ else
102
+ clase.human_attribute_name(campo)
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgRails
4
+ module FormHelper
5
+ def pg_form_for(object, *args, &block)
6
+ options = args.extract_options!
7
+
8
+ options[:builder] = PgFormBuilder
9
+ options[:html] ||= {}
10
+ options[:html][:class] = if options[:html].key?(:class)
11
+ ['pg-form', options[:html][:class]].compact
12
+ else
13
+ 'pg-form'
14
+ end
15
+
16
+ simple_form_for(object, *(args << options), &block)
17
+ end
18
+
19
+ def url_change_format(url)
20
+ uri = URI.parse(url)
21
+ uri.path = "#{uri.path}.xlsx"
22
+ uri.to_s
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgRails
4
+ module PostgresHelper
5
+ # Le pone la timezone
6
+ def add_timezone(field)
7
+ "#{field}::TIMESTAMPTZ AT TIME ZONE INTERVAL '-03:00'::INTERVAL"
8
+ end
9
+
10
+ # Le pone la timezone y lo convierte a Date
11
+ def get_date_tz(field)
12
+ "(#{add_timezone(field)})::date"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgRails
4
+ module PrintHelper
5
+ include ActionView::Helpers::NumberHelper
6
+
7
+ class FechaInvalidaError < StandardError
8
+ end
9
+
10
+ # Genera un falso link que al clickear carga la url por ajax
11
+ # Es igual a los links con remote: true, pero evita que abran el link en otra
12
+ # pestaña. Movido de probella
13
+ def pg_ajax_link(url, options = {})
14
+ content_tag :span, class: 'pg_ajax_link', data: options.merge(url: url) do
15
+ block_given? ? yield : ''
16
+ end
17
+ end
18
+
19
+ def mostrar_con_link(objeto, options = {})
20
+ return unless objeto.present?
21
+
22
+ if policy(objeto).show?
23
+ content = truncate_title(block_given? ? yield : objeto)
24
+ if options[:new_tab]
25
+ content += "&nbsp;<i class='fa fa-external-link'>".html_safe
26
+ link_to content.html_safe, objeto, target: :_blank
27
+ else
28
+ link_to content.html_safe, objeto
29
+ end
30
+ else
31
+ truncate_title(block_given? ? yield : objeto)
32
+ end
33
+ end
34
+
35
+ def truncate_title(input, length = 20)
36
+ string = input.to_s
37
+ if string.length > length
38
+ content_tag :span, title: input, rel: :tooltip do
39
+ truncate string, length: length
40
+ end
41
+ else
42
+ string
43
+ end
44
+ end
45
+
46
+ def print_cuit(cuit_number)
47
+ return '' unless cuit_number.present?
48
+
49
+ str = cuit_number.to_s
50
+ "#{str[0..1]}-#{str[2..9]}-#{str[10]}"
51
+ end
52
+
53
+ def dmy_time(date)
54
+ date = parsear_tiempo(date) if date.is_a? String
55
+ return unless date.present?
56
+
57
+ date.strftime('%d/%m/%Y %H:%M')
58
+ end
59
+
60
+ def dmy(date)
61
+ date = parsear_fecha(date) if date.is_a? String
62
+ return unless date.present?
63
+
64
+ date.strftime('%d/%m/%Y')
65
+ end
66
+
67
+ def ymd(date)
68
+ date = parsear_fecha(date) if date.is_a? String
69
+ return unless date.present?
70
+
71
+ date.strftime('%Y/%m/%d')
72
+ end
73
+
74
+ def dmyg(date)
75
+ date = parsear_fecha(date) if date.is_a? String
76
+ return unless date.present?
77
+
78
+ date.strftime('%d-%m-%Y')
79
+ end
80
+
81
+ def ymdg(date)
82
+ date = parsear_fecha(date) if date.is_a? String
83
+ return unless date.present?
84
+
85
+ date.strftime('%Y-%m-%d')
86
+ end
87
+
88
+ def myg(date)
89
+ date = parsear_fecha(date) if date.is_a? String
90
+ return unless date.present?
91
+
92
+ date.strftime('%m-%Y')
93
+ end
94
+
95
+ def print_number(number)
96
+ number_with_precision(number, delimiter: ',', separator: '.', precision: 2)
97
+ end
98
+
99
+ def print_number_coma(number)
100
+ number_with_precision(number, delimiter: '.', separator: ',', precision: 2)
101
+ end
102
+
103
+ def print_boolean(boolean)
104
+ return if boolean.nil?
105
+ return 'Si' if boolean
106
+
107
+ 'No'
108
+ end
109
+
110
+ def print_currency(number, moneda = 'pesos')
111
+ return unless number.present?
112
+
113
+ "<span class='currency #{moneda}'>#{number_with_precision(number, delimiter: '.',
114
+ separator: ',', precision: 2)}</span>".html_safe
115
+ end
116
+
117
+ def print_currency2(number, moneda = 'pesos')
118
+ return unless number.present?
119
+
120
+ "#{simbolo_moneda(moneda)} #{number_with_precision(number, delimiter: '.', separator: ',',
121
+ precision: 2)}"
122
+ end
123
+
124
+ def simbolo_moneda(moneda)
125
+ return '$' if moneda == 'pesos'
126
+ return 'U$S' if moneda == 'dolares'
127
+ return '€' if moneda == 'euros'
128
+ return 'R$' if moneda == 'reales'
129
+ return 'CLP' if moneda == 'pesos_chilenos'
130
+ return 'MXN' if moneda == 'pesos_mexicanos'
131
+
132
+ '$'
133
+ end
134
+
135
+ def print_value(nombre_clase, field, value)
136
+ if !value.nil? == value # es booleano
137
+ value ? 'Si' : 'No'
138
+ elsif value.nil?
139
+ '-'
140
+ else
141
+ begin
142
+ if nombre_clase.constantize.defined_enums[field].present?
143
+ valor = nombre_clase.constantize.defined_enums[field].invert[value]
144
+ I18n.t("enums.#{nombre_clase.downcase}.#{field}.#{valor}", default: valor)
145
+ else
146
+ truncate_title(value.to_s.encode('UTF-8', invalid: :replace, undef: :replace))
147
+ end
148
+ rescue NameError
149
+ truncate_title(value.to_s.encode('UTF-8', invalid: :replace, undef: :replace))
150
+ end
151
+ end
152
+ end
153
+
154
+ def parsear_tiempo(datetime)
155
+ return nil unless datetime.present?
156
+
157
+ DateTime.parse(datetime)
158
+ rescue ArgumentError
159
+ raise FechaInvalidaError, datetime
160
+ end
161
+
162
+ def parsear_fecha(date)
163
+ return nil unless date.present?
164
+
165
+ Date.parse(date)
166
+ rescue ArgumentError
167
+ raise FechaInvalidaError, date
168
+ end
169
+
170
+ def show_percentage(value)
171
+ return unless value.present?
172
+
173
+ "#{value.round(2)} %"
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgRails
4
+ class AsociacionCreableInput < SimpleForm::Inputs::StringInput
5
+ include ActionView::Helpers::FormTagHelper
6
+
7
+ def boton(wrapper_options = {})
8
+ if PgRails.config.bootstrap_version >= 4
9
+ button_tag('', wrapper_options)
10
+ else
11
+ button_tag('<span class="caret">'.html_safe, wrapper_options)
12
+ end
13
+ end
14
+
15
+ def hidden_input(wrapper_options = {})
16
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
17
+ merged_input_options = merge_wrapper_options(merged_input_options, { class: 'oculto' })
18
+ @builder.text_field(attribute_name, merged_input_options)
19
+ end
20
+
21
+ def input(wrapper_options = nil)
22
+ unless string?
23
+ input_html_classes.unshift('string')
24
+ input_html_options[:type] ||= input_type if html5?
25
+ end
26
+
27
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
28
+ merged_input_options = merge_wrapper_options(merged_input_options, { class: 'keep-disabled' })
29
+
30
+ text_field_tag(nil, object.send(reflection.name).to_s, merged_input_options)
31
+ end
32
+
33
+ def seleccionar_asociado(wrapper_options = {})
34
+ icon = content_tag :span, nil, class: 'fa fa-hand-pointer'
35
+ merged_input_options = merge_wrapper_options(wrapper_options,
36
+ { class: 'seleccionar_asociado dropdown-item', href: 'javascript:void(0)',
37
+ data: { url: options[:url_seleccionar] } })
38
+ anchor = content_tag :a, "#{icon} Seleccionar".html_safe, merged_input_options
39
+ if PgRails.config.bootstrap_version >= 4
40
+ anchor
41
+ else
42
+ "<li>#{anchor}</li>".html_safe
43
+ end
44
+ end
45
+
46
+ def crear_asociado(wrapper_options = {})
47
+ icon = content_tag :span, nil, class: 'fa fa-plus-square'
48
+ merged_input_options = merge_wrapper_options(wrapper_options,
49
+ { class: 'crear_asociado dropdown-item', href: 'javascript:void(0)',
50
+ data: { url: options[:url_crear] } })
51
+ anchor = content_tag :a, "#{icon} Crear".html_safe, merged_input_options
52
+ if PgRails.config.bootstrap_version >= 4
53
+ anchor
54
+ else
55
+ "<li>#{anchor}</li>".html_safe
56
+ end
57
+ end
58
+
59
+ def borrar_seleccion(wrapper_options = {})
60
+ icon = content_tag :span, nil, class: 'fa fa-trash'
61
+ merged_input_options = merge_wrapper_options(wrapper_options,
62
+ { class: 'borrar_seleccion dropdown-item',
63
+ href: 'javascript:void(0)' })
64
+ anchor = content_tag :a, "#{icon} Borrar selección".html_safe, merged_input_options
65
+ if PgRails.config.bootstrap_version >= 4
66
+ anchor
67
+ else
68
+ "<li>#{anchor}</li>".html_safe
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgRails
4
+ class FechaInput < SimpleForm::Inputs::StringInput
5
+ def input(wrapper_options = nil)
6
+ # esto es porque si no Rails llama a value_before_type_cast
7
+ if object.is_a? Draper::Decorator
8
+ # Salteo el decorator para que me tome la fecha con formato inglés
9
+ value = object.object.public_send(attribute_name)
10
+ else
11
+ value = object.public_send(attribute_name)
12
+ end
13
+ @input_type = 'date'
14
+
15
+ options = merge_wrapper_options({ value: value, class: '', autocomplete: 'off' },
16
+ wrapper_options)
17
+ super(options)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PgRails
4
+ class SelectsDependientesInput < SimpleForm::Inputs::CollectionSelectInput
5
+ include ActionView::Helpers::FormOptionsHelper
6
+
7
+ # TODO
8
+ end
9
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # TODO: fix hackeo
4
+ # class PgFormBuilder < NestedForm::SimpleBuilder
5
+ class PgFormBuilder < SimpleForm::FormBuilder
6
+ def mensajes_de_error
7
+ return unless object.errors.present?
8
+
9
+ errors = object.errors.full_messages.map { |m| "<li>#{m}</li>" }.join
10
+ "<div class='alert alert-danger'>#{errors}</div>".html_safe
11
+ end
12
+
13
+ map_type :date, to: PgRails::FechaInput
14
+ # map_type :datetime, to: PgRails::FechaInput
15
+
16
+ def asociacion_creable(atributo, url_seleccionar, url_crear, options = {})
17
+ options[:as] = 'pg_rails/asociacion_creable'
18
+ options[:wrapper] = :asociacion_creable
19
+ options[:url_seleccionar] = url_seleccionar
20
+ options[:url_crear] = url_crear
21
+ options[:wrapper_html] = { class: 'completado' } if object.send(atributo).present?
22
+ association atributo, options
23
+ end
24
+
25
+ def submit_button(*args, &block)
26
+ options = args.extract_options!.dup
27
+ options[:class] = ['btn-primary', options[:class]].compact
28
+ args << options
29
+ send(:submit, *args, &block)
30
+ end
31
+ end