pg_rails 7.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +73 -0
- data/Rakefile +36 -0
- data/app/assets/javascripts/pg_rails/asociacion_creable.js +85 -0
- data/app/assets/javascripts/pg_rails/best_in_place_datepicker.js +58 -0
- data/app/assets/javascripts/pg_rails/librerias.js +13 -0
- data/app/assets/javascripts/pg_rails/librerias_b3.js +14 -0
- data/app/assets/javascripts/pg_rails/validaciones.js +44 -0
- data/app/assets/javascripts/pg_rails.js +318 -0
- data/app/assets/stylesheets/pg_rails/librerias.scss +5 -0
- data/app/assets/stylesheets/pg_rails/pg_chosen.scss +29 -0
- data/app/assets/stylesheets/pg_rails/pg_rails.scss +199 -0
- data/app/assets/stylesheets/pg_rails_b3.scss +10 -0
- data/app/assets/stylesheets/pg_rails_b4.scss +12 -0
- data/app/assets/stylesheets/pg_rails_b5.scss +1 -0
- data/app/controllers/pg_rails/application_controller.rb +316 -0
- data/app/controllers/pg_rails/editar_en_lugar_controller.rb +24 -0
- data/app/decorators/pg_rails/base_decorator.rb +120 -0
- data/app/helpers/pg_rails/editar_en_lugar_helper.rb +106 -0
- data/app/helpers/pg_rails/form_helper.rb +25 -0
- data/app/helpers/pg_rails/postgres_helper.rb +15 -0
- data/app/helpers/pg_rails/print_helper.rb +176 -0
- data/app/inputs/pg_rails/asociacion_creable_input.rb +72 -0
- data/app/inputs/pg_rails/fecha_input.rb +20 -0
- data/app/inputs/pg_rails/selects_dependientes_input.rb +9 -0
- data/app/lib/pg_form_builder.rb +31 -0
- data/app/lib/pg_rails/filtros_builder.rb +338 -0
- data/app/models/pg_rails/application_record.rb +51 -0
- data/app/policies/pg_rails/application_policy.rb +104 -0
- data/app/views/application/_abrir_modal.js.erb +14 -0
- data/app/views/application/_actualizar_smart_listing.html.slim +3 -0
- data/app/views/application/_cerrar_modal.js.erb +8 -0
- data/app/views/application/_modal_ajax_form.js.erb +7 -0
- data/config/brakeman.ignore +42 -0
- data/config/locales/es.yml +17 -0
- data/config/routes.rb +3 -0
- data/config/spring.rb +1 -0
- data/lib/pg_rails/configuracion.rb +24 -0
- data/lib/pg_rails/core_ext.rb +17 -0
- data/lib/pg_rails/engine.rb +42 -0
- data/lib/pg_rails/simple_form/initializer.rb +583 -0
- data/lib/pg_rails/utils/logueador.rb +39 -0
- data/lib/pg_rails/version.rb +5 -0
- data/lib/pg_rails.rb +23 -0
- data/lib/tasks/auto_anotar_modelos.rake +34 -0
- data/lib/tasks/pg_rails_tasks.rake +5 -0
- 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 += " <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,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
|