mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-09-12 21:37:23 -04:00
* fix(xss): remove redundant escaping that double-encoded item attribute values - Remove esc()/html_entity_decode() calls now that output is escaped at render time by the framework, preventing double-encoding of special characters in attribute names, units, and definition values - Fix employee_name form_input value fields to stop pre-escaping before form_input applies its own escaping - Reorder Items.php use statements and add missing BaseConnection import - Change items/manage.php start_date from let to plain assignment for proper reassignment scope Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * test(sales): add regression tests for permission checks on sales endpoints - Ensure role-based permissions correctly restrict access to sensitive actions like price edits, receipt/invoice views, and report generation. - Add tests for both granted and restricted user scenarios to validate the behavior. Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * fix(attributes): validate `attribute_value` before processing - Add checks to ensure `attribute_value` is a non-empty string in `postSaveAttributeValue` and `postDeleteDropdownAttributeValue` methods. - Return error response if validation fails to prevent invalid data handling. Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * fix(attributes): improve error handling and optimize affected items processing - Use `array_column` for extracting item IDs to streamline logic. - Add JSON validation with `JSON_THROW_ON_ERROR` and return proper error response for invalid `definition_values`. Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * test(sales): enable database refresh for consistent test state Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * test(sales): assert unauthorized message is displayed on restricted access Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * refactor(attributes): use camelCase for `attributeValue` in controller methods - Standardize variable naming in `postSaveAttributeValue` and `postDeleteDropdownAttributeValue` methods by switching to camelCase. Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> --------- Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> Co-authored-by: Travis Garrison <travis@chiraqbookstore.com>
168 lines
7.6 KiB
PHP
168 lines
7.6 KiB
PHP
<?php
|
|
/**
|
|
* @var array $definition_names
|
|
* @var array $definition_values
|
|
* @var int $item_id
|
|
* @var array $config
|
|
*/
|
|
?>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Attributes.definition_name'), 'definition_name_label', ['class' => 'control-label col-xs-3']) ?>
|
|
<div class="col-xs-8">
|
|
<?= form_dropdown([
|
|
'name' => 'definition_name',
|
|
'options' => $definition_names,
|
|
'selected' => -1,
|
|
'class' => 'form-control',
|
|
'id' => 'definition_name'
|
|
]) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<?php foreach ($definition_values as $definition_id => $definition_value) { ?>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(esc($definition_value['definition_name']), esc($definition_value['definition_name']), ['class' => 'control-label col-xs-3']) ?>
|
|
<div class="col-xs-8">
|
|
<div class="input-group">
|
|
<?php
|
|
echo form_hidden("attribute_ids[$definition_id]", strval($definition_value['attribute_id']));
|
|
$attribute_value = $definition_value['attribute_value'];
|
|
|
|
switch ($definition_value['definition_type']) {
|
|
case DATE:
|
|
$value = (empty($attribute_value) || empty($attribute_value->attribute_date)) ? NOW : strtotime($attribute_value->attribute_date);
|
|
echo form_input([
|
|
'name' => "attribute_links[$definition_id]",
|
|
'value' => to_date($value),
|
|
'class' => 'form-control input-sm datetime',
|
|
'data-definition-id' => $definition_id,
|
|
'readonly' => 'true'
|
|
]);
|
|
break;
|
|
case DROPDOWN:
|
|
$selected_value = $definition_value['selected_value'];
|
|
echo form_dropdown([
|
|
'name' => "attribute_links[$definition_id]",
|
|
'options' => $definition_value['values'],
|
|
'selected' => $selected_value,
|
|
'class' => 'form-control',
|
|
'data-definition-id' => $definition_id
|
|
]);
|
|
break;
|
|
case TEXT:
|
|
$value = (empty($attribute_value) || empty($attribute_value->attribute_value)) ? $definition_value['selected_value'] : $attribute_value->attribute_value;
|
|
echo form_input([
|
|
'name' => "attribute_links[$definition_id]",
|
|
'value' => $value,
|
|
'class' => 'form-control valid_chars',
|
|
'data-definition-id' => $definition_id
|
|
]);
|
|
break;
|
|
case DECIMAL:
|
|
$value = (empty($attribute_value) || empty($attribute_value->attribute_decimal)) ? $definition_value['selected_value'] : $attribute_value->attribute_decimal;
|
|
echo form_input([
|
|
'name' => "attribute_links[$definition_id]",
|
|
'value' => to_decimals((float)$value),
|
|
'class' => 'form-control valid_chars',
|
|
'data-definition-id' => $definition_id
|
|
]);
|
|
break;
|
|
case CHECKBOX:
|
|
$value = (empty($attribute_value) || empty($attribute_value->attribute_value)) ? $definition_value['selected_value'] : $attribute_value->attribute_value;
|
|
|
|
// Sends 0 if the box is unchecked instead of not sending anything.
|
|
echo form_input([
|
|
'type' => 'hidden',
|
|
'name' => "attribute_links[$definition_id]",
|
|
'id' => "attribute_links[$definition_id]",
|
|
'value' => 0,
|
|
'data-definition-id' => $definition_id
|
|
]);
|
|
echo form_checkbox([
|
|
'name' => "attribute_links[$definition_id]",
|
|
'id' => "attribute_links[$definition_id]",
|
|
'value' => 1,
|
|
'checked' => $value == 1,
|
|
'class' => 'checkbox-inline',
|
|
'data-definition-id' => $definition_id
|
|
]);
|
|
break;
|
|
}
|
|
?>
|
|
<span class="input-group-addon input-sm btn btn-default remove_attribute_btn">
|
|
<span class="glyphicon glyphicon-trash"></span>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php } ?>
|
|
|
|
<script type="text/javascript">
|
|
(function() {
|
|
<?= view('partial/datepicker_locale', ['format' => dateformat_bootstrap($config['dateformat'])]) ?>
|
|
|
|
const enable_delete = function() {
|
|
$('.remove_attribute_btn').click(function() {
|
|
$(this).parents('.form-group').remove();
|
|
});
|
|
};
|
|
|
|
enable_delete();
|
|
|
|
$("input[name*='attribute_links']").change(function() {
|
|
const definition_id = $(this).data('definition-id');
|
|
$("input[name='attribute_ids[" + definition_id + "]']").val('');
|
|
}).autocomplete({
|
|
source: function(request, response) {
|
|
$.get('<?= 'attributes/suggestAttribute/' ?>' + this.element.data('definition-id') + '?term=' + request.term, function(data) {
|
|
return response(data);
|
|
}, 'json');
|
|
},
|
|
appendTo: '.modal-content',
|
|
select: function(event, ui) {
|
|
event.preventDefault();
|
|
$(this).val(ui.item.label);
|
|
},
|
|
delay: 10
|
|
});
|
|
|
|
const definition_values = function() {
|
|
const result = {};
|
|
$("[name*='attribute_links'").each(function() {
|
|
const definition_id = $(this).data('definition-id');
|
|
const element = $(this);
|
|
|
|
// For checkboxes, use the visible checkbox, not the hidden input
|
|
if (element.attr('type') === 'hidden' && element.siblings('input[type="checkbox"]').length > 0) {
|
|
// Skip hidden inputs that have a corresponding checkbox
|
|
return;
|
|
}
|
|
|
|
// For checkboxes, get the checked state
|
|
if (element.attr('type') === 'checkbox') {
|
|
result[definition_id] = element.prop('checked') ? '1' : '0';
|
|
} else {
|
|
result[definition_id] = element.val();
|
|
}
|
|
});
|
|
return result;
|
|
};
|
|
|
|
const refresh = function() {
|
|
const definition_id = $("#definition_name option:selected").val();
|
|
let attribute_values = definition_values();
|
|
attribute_values[definition_id] = '';
|
|
$('#attributes').load('<?= "items/attributes/$item_id" ?>', {
|
|
'definition_ids': JSON.stringify(attribute_values)
|
|
}, enable_delete);
|
|
};
|
|
|
|
$('#definition_name').change(function() {
|
|
refresh();
|
|
});
|
|
})();
|
|
</script>
|