Skip to content

Commit 4613f02

Browse files
saulmoralespaCopilot
andcommitted
feat: Update payment mapping settings and validation logic
- Enhanced the description in settings to clarify the requirements for payment types and methods. - Modified the payment mappings table to include data attributes for live UX validation. - Updated validation logic to allow saving gateways with empty account_id when payment_method is provided. - Implemented checks to ensure payment_method is required for CASH payment_type, while CREDIT can be saved without it. - Adjusted invoice generation logic to omit paymentMethod when it is empty, ensuring correct payload structure. - Added tests to validate the new behavior and ensure proper handling of payment mappings. - Bumped version to 0.1.2 and updated changelog for clarity on changes made. Co-authored-by: Copilot <copilot@github.com>
1 parent a89180a commit 4613f02

9 files changed

Lines changed: 840 additions & 86 deletions
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/**
2+
* Admin Payment Mappings — Integration Alegra WooCommerce
3+
*
4+
* Resalta el campo "Forma de pago" cuando el "Tipo de pago" es CASH y el campo
5+
* está vacío. Deshabilita el botón "Guardar cambios" mientras exista al menos
6+
* una fila con esa combinación inválida (aplica a gateways activos e inactivos
7+
* que aparezcan en la tabla).
8+
*/
9+
(function ($) {
10+
'use strict';
11+
12+
var TABLE = '#alegra-payment-mappings-table';
13+
var SAVE_BTN = 'button.woocommerce-save-button';
14+
var CASH_TYPE = (typeof alegraPaymentMappings !== 'undefined') ? alegraPaymentMappings.cashType : 'CASH';
15+
16+
// ── Estilos ──────────────────────────────────────────────────────────────
17+
18+
$('<style>').text(
19+
'#alegra-mapping-errors{' +
20+
'background:#fcf0f1;border-left:4px solid #d63638;' +
21+
'padding:10px 14px;margin:0 0 10px;border-radius:2px' +
22+
'}' +
23+
'#alegra-mapping-errors p{margin:4px 0;color:#d63638;font-weight:600}' +
24+
'#alegra-mapping-errors ul{margin:4px 0 0 18px;list-style:disc;color:#50575e}' +
25+
'select.alegra-field-error{' +
26+
'outline:2px solid #d63638 !important;' +
27+
'border-color:#d63638 !important' +
28+
'}'
29+
).appendTo('head');
30+
31+
// ── Helpers ───────────────────────────────────────────────────────────────
32+
33+
/**
34+
* Escapa HTML para usar en literales de innerHTML.
35+
*/
36+
function escHtml(str) {
37+
return $('<div>').text(str).html();
38+
}
39+
40+
/**
41+
* Recorre todas las filas de la tabla y devuelve un array con información
42+
* de las filas inválidas (CASH + Forma de pago vacía).
43+
* Como efecto secundario, elimina el marcado de error de las filas válidas.
44+
*
45+
* @returns {Array<{id: string, label: string, $methodSelect: jQuery}>}
46+
*/
47+
function collectInvalidRows() {
48+
var errors = [];
49+
50+
$(TABLE + ' tbody tr[data-alegra-gateway-id]').each(function () {
51+
var $row = $(this);
52+
var $typeSelect = $row.find('select[data-alegra-field="payment_type"]');
53+
var $methodSelect = $row.find('select[data-alegra-field="payment_method"]');
54+
55+
var isCash = $typeSelect.val() === CASH_TYPE;
56+
var isEmpty = $methodSelect.val() === '';
57+
58+
if (isCash && isEmpty) {
59+
var label = $row.data('alegra-gateway-label') || $row.data('alegra-gateway-id');
60+
errors.push({ id: $row.data('alegra-gateway-id'), label: label, $methodSelect: $methodSelect });
61+
} else {
62+
// Fila válida: limpiar marcado de error previo.
63+
$methodSelect.removeClass('alegra-field-error').removeAttr('aria-invalid');
64+
}
65+
});
66+
67+
return errors;
68+
}
69+
70+
/**
71+
* Ejecuta validación completa:
72+
* - Resalta selects inválidos con clase de error y aria-invalid.
73+
* - Muestra/oculta el bloque de mensaje detallado.
74+
* - Habilita/deshabilita el botón Guardar cambios.
75+
*/
76+
function validate() {
77+
var errors = collectInvalidRows();
78+
var $errorBox = $('#alegra-mapping-errors');
79+
80+
if (errors.length > 0) {
81+
// Marcar cada select inválido.
82+
$.each(errors, function (i, e) {
83+
e.$methodSelect.addClass('alegra-field-error').attr('aria-invalid', 'true');
84+
});
85+
86+
// Construir mensaje detallado listando gateways con error.
87+
var items = $.map(errors, function (e) {
88+
return '<li>' +
89+
'<strong>' + escHtml(e.label) + '</strong>' +
90+
': la Forma de pago es obligatoria cuando el Tipo de pago es Contado (CASH).' +
91+
'</li>';
92+
}).join('');
93+
94+
var html = '<p>No se pueden guardar los cambios. Completa los campos requeridos:</p>' +
95+
'<ul>' + items + '</ul>';
96+
97+
if ($errorBox.length === 0) {
98+
$errorBox = $('<div id="alegra-mapping-errors">').insertBefore(TABLE);
99+
}
100+
$errorBox.html(html);
101+
102+
$(SAVE_BTN).prop('disabled', true);
103+
104+
} else {
105+
// Sin errores: limpiar todo y habilitar guardado.
106+
$errorBox.remove();
107+
$(SAVE_BTN).prop('disabled', false);
108+
}
109+
}
110+
111+
// ── Inicialización ────────────────────────────────────────────────────────
112+
113+
$(function () {
114+
if ($(TABLE).length === 0) {
115+
return; // Tabla no presente en esta pantalla.
116+
}
117+
118+
// Validación inicial: cubre el caso de datos ya guardados en estado inválido.
119+
validate();
120+
121+
// Re-validar en cualquier cambio de tipo o forma de pago en la tabla.
122+
$(document).on(
123+
'change',
124+
TABLE + ' select[data-alegra-field="payment_type"],' +
125+
TABLE + ' select[data-alegra-field="payment_method"]',
126+
validate
127+
);
128+
});
129+
130+
})(jQuery);

includes/admin/other_settings.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
'bank_accounts' => $bank_accounts,
100100
'active_gateways' => $active_gateways,
101101
'all_gateways' => $all_gateways,
102-
'description' => __( 'Debe configurar método de pago, cuenta bancaria y tipo de pago para cada gateway activo. Los gateways inactivos con mapeo guardado también se muestran para edición.' ),
102+
'description' => __( 'Configure el tipo de pago para cada gateway. Cuando el tipo es <strong>Contado (CASH)</strong>, la Forma de pago es obligatoria. Cuando es <strong>Crédito (CREDIT)</strong>, la Forma de pago es opcional. La Cuenta bancaria siempre es opcional. Los gateways inactivos con mapeo guardado también se muestran para edición.' ),
103103
'desc_tip' => false
104104
),
105105
'client' => array(

includes/class-alegra-integration-wc.php

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -175,13 +175,13 @@ public function generate_payment_mappings_table_html($key, $data): string
175175
<?php if ( empty($rows) ): ?>
176176
<p><?php echo esc_html__('No hay métodos de pago activos disponibles en WooCommerce para mapear.', 'integration-alegra-woo'); ?></p>
177177
<?php else: ?>
178-
<table class="widefat striped">
178+
<table class="widefat striped" id="alegra-payment-mappings-table">
179179
<thead>
180180
<tr>
181181
<th><?php echo esc_html__('Gateway WooCommerce', 'integration-alegra-woo'); ?></th>
182182
<th><?php echo esc_html__('Tipo de pago', 'integration-alegra-woo'); ?></th>
183-
<th><?php echo esc_html__('Cuenta bancaria en Alegra', 'integration-alegra-woo'); ?></th>
184183
<th><?php echo esc_html__('Forma de pago', 'integration-alegra-woo'); ?></th>
184+
<th><?php echo esc_html__('Cuenta bancaria en Alegra', 'integration-alegra-woo'); ?></th>
185185
</tr>
186186
</thead>
187187
<tbody>
@@ -196,14 +196,24 @@ public function generate_payment_mappings_table_html($key, $data): string
196196
$gateway_label .= ' (' . __('inactivo', 'integration-alegra-woo') . ')';
197197
}
198198
?>
199-
<tr>
199+
<tr data-alegra-gateway-id="<?php echo esc_attr($gateway_id); ?>" data-alegra-gateway-label="<?php echo esc_attr($gateway_label); ?>" data-alegra-active="<?php echo $gateway_data['active'] ? '1' : '0'; ?>">
200200
<td>
201201
<strong><?php echo esc_html($gateway_label); ?></strong>
202202
<br/>
203203
<small><?php echo esc_html($gateway_id); ?></small>
204204
</td>
205205
<td>
206-
<select name="<?php echo esc_attr(sprintf('%s[%s][payment_method]', $field_key, $gateway_id)); ?>">
206+
<select name="<?php echo esc_attr(sprintf('%s[%s][payment_type]', $field_key, $gateway_id)); ?>" data-alegra-field="payment_type">
207+
<option value=""><?php echo esc_html__('Seleccionar tipo...', 'integration-alegra-woo'); ?></option>
208+
<?php foreach ($data['payment_types'] as $type_key => $type_label): ?>
209+
<option value="<?php echo esc_attr($type_key); ?>" <?php selected($saved_type, $type_key); ?>>
210+
<?php echo esc_html($type_label); ?>
211+
</option>
212+
<?php endforeach; ?>
213+
</select>
214+
</td>
215+
<td>
216+
<select name="<?php echo esc_attr(sprintf('%s[%s][payment_method]', $field_key, $gateway_id)); ?>" data-alegra-field="payment_method">
207217
<option value=""><?php echo esc_html__('Seleccionar método...', 'integration-alegra-woo'); ?></option>
208218
<?php foreach ($data['payment_methods'] as $method_key => $method_label): ?>
209219
<option value="<?php echo esc_attr($method_key); ?>" <?php selected($saved_method, $method_key); ?>>
@@ -222,16 +232,6 @@ public function generate_payment_mappings_table_html($key, $data): string
222232
<?php endforeach; ?>
223233
</select>
224234
</td>
225-
<td>
226-
<select name="<?php echo esc_attr(sprintf('%s[%s][payment_type]', $field_key, $gateway_id)); ?>">
227-
<option value=""><?php echo esc_html__('Seleccionar tipo...', 'integration-alegra-woo'); ?></option>
228-
<?php foreach ($data['payment_types'] as $type_key => $type_label): ?>
229-
<option value="<?php echo esc_attr($type_key); ?>" <?php selected($saved_type, $type_key); ?>>
230-
<?php echo esc_html($type_label); ?>
231-
</option>
232-
<?php endforeach; ?>
233-
</select>
234-
</td>
235235
</tr>
236236
<?php endforeach; ?>
237237
</tbody>
@@ -276,10 +276,13 @@ public function validate_payment_mappings_table_field($key, $value): array
276276
}
277277

278278
if (empty($available_bank_accounts)) {
279-
WC_Admin_Settings::add_error(
280-
__('Integration Alegra Woocommerce: No se encontraron cuentas bancarias activas en Alegra para guardar el mapeo de pagos.', 'integration-alegra-woo')
281-
);
282-
return $existing_value;
279+
$any_account_id = ! empty( array_filter( array_column( $sanitized_mapping, 'account_id' ) ) );
280+
if ( $any_account_id ) {
281+
WC_Admin_Settings::add_error(
282+
__('Integration Alegra Woocommerce: No se encontraron cuentas bancarias activas en Alegra para guardar el mapeo de pagos.', 'integration-alegra-woo')
283+
);
284+
return $existing_value;
285+
}
283286
}
284287

285288
$has_errors = false;
@@ -292,10 +295,14 @@ public function validate_payment_mappings_table_field($key, $value): array
292295
'payment_type' => '',
293296
];
294297

295-
if (!$gateway_map['payment_method'] || !$gateway_map['account_id'] || !$gateway_map['payment_type']) {
298+
$cash_without_method = (
299+
$gateway_map['payment_type'] === Integration_Alegra_WC::PAYMENT_TYPE_CASH
300+
&& ! $gateway_map['payment_method']
301+
);
302+
if ( ! $gateway_map['payment_type'] || $cash_without_method ) {
296303
WC_Admin_Settings::add_error(
297304
sprintf(
298-
__('Integration Alegra Woocommerce: Debe configurar método de pago, cuenta bancaria y tipo de pago para el gateway activo "%s".', 'integration-alegra-woo'),
305+
__('Integration Alegra Woocommerce: Debe configurar el tipo de pago para el gateway activo "%s". Si el tipo de pago es CASH, también debe configurar la Forma de pago.', 'integration-alegra-woo'),
299306
$gateway_title
300307
)
301308
);
@@ -307,37 +314,30 @@ public function validate_payment_mappings_table_field($key, $value): array
307314
$payment_method = $gateway_map['payment_method'];
308315
$account_id = $gateway_map['account_id'];
309316

310-
if (($payment_method && !$account_id) || (!$payment_method && $account_id)) {
311-
WC_Admin_Settings::add_error(
312-
sprintf(
313-
__('Integration Alegra Woocommerce: El gateway "%s" tiene configuración incompleta. Debe seleccionar método y cuenta.', 'integration-alegra-woo'),
314-
$gateway_id
315-
)
316-
);
317-
$has_errors = true;
318-
continue;
319-
}
320-
321-
if (!$payment_method && !$account_id) {
317+
// payment_method is required only for CASH; silently skip those rows.
318+
$row_payment_type = $gateway_map['payment_type'] ?? '';
319+
if ( ! $payment_method && $row_payment_type !== Integration_Alegra_WC::PAYMENT_TYPE_CREDIT ) {
322320
continue;
323321
}
324322

325-
// Accept only UBL catalog codes.
326-
$is_ubl = isset( Integration_Alegra_WC::PAYMENTS_METHODS[ $payment_method ] );
327-
328-
if ( ! $is_ubl ) {
329-
WC_Admin_Settings::add_error(
330-
sprintf(
331-
__('Integration Alegra Woocommerce: El método de pago "%s" no es válido para el gateway "%s".', 'integration-alegra-woo'),
332-
$payment_method,
333-
$gateway_id
334-
)
335-
);
336-
$has_errors = true;
337-
continue;
323+
// Accept only UBL catalog codes (when payment_method is present).
324+
if ( $payment_method ) {
325+
$is_ubl = isset( Integration_Alegra_WC::PAYMENTS_METHODS[ $payment_method ] );
326+
327+
if ( ! $is_ubl ) {
328+
WC_Admin_Settings::add_error(
329+
sprintf(
330+
__('Integration Alegra Woocommerce: El método de pago "%s" no es válido para el gateway "%s".', 'integration-alegra-woo'),
331+
$payment_method,
332+
$gateway_id
333+
)
334+
);
335+
$has_errors = true;
336+
continue;
337+
}
338338
}
339339

340-
if (!isset($available_bank_accounts[$account_id])) {
340+
if ( $account_id && !isset($available_bank_accounts[$account_id])) {
341341
WC_Admin_Settings::add_error(
342342
sprintf(
343343
__('Integration Alegra Woocommerce: La cuenta bancaria "%s" no es válida para el gateway "%s".', 'integration-alegra-woo'),

includes/class-integration-alegra-wc-plugin.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,30 @@ public function enqueue_scripts_admin($hook): void
385385
wp_enqueue_script( 'integration-alegra', $this->assets. 'js/integration-alegra.js', array( 'jquery' ), $this->version, true );
386386
wp_enqueue_script( 'integration-alegra-sweet-alert', $this->assets. 'js/sweetalert2.min.js', array( 'jquery' ), $this->version, true );
387387
}
388+
389+
// Validación UX en vivo para la tabla de mapeo de métodos de pago.
390+
$is_payment_mapping_screen = (
391+
$hook === 'woocommerce_page_wc-settings'
392+
&& isset( $_GET['tab'] ) && 'integration' === $_GET['tab']
393+
&& isset( $_GET['section'] ) && 'wc_alegra_integration' === $_GET['section']
394+
);
395+
396+
if ( $is_payment_mapping_screen ) {
397+
wp_enqueue_script(
398+
'integration-alegra-payment-mappings',
399+
$this->assets . 'js/admin-payment-mappings.js',
400+
array( 'jquery' ),
401+
$this->version,
402+
true
403+
);
404+
wp_localize_script(
405+
'integration-alegra-payment-mappings',
406+
'alegraPaymentMappings',
407+
array(
408+
'cashType' => Integration_Alegra_WC::PAYMENT_TYPE_CASH,
409+
)
410+
);
411+
}
388412
}
389413

390414
public function enqueue_scripts(): void

0 commit comments

Comments
 (0)