mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-07-26 14:47:06 -04:00
* Add `reference_code` to sale payment queries and group by statements Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * Refactor `Sales` controller to improve payment handling readability and replace snake_case with camelCase variables Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * Add missing translations for `Sales` language file and include new keys like `must_enter_rrn` and `reference_code` Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * Refactor `Sales` payment handling to use camelCase and extend `addPayment` with `referenceCode` support Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * Refactor `Sales` models, controllers, and libraries to adopt camelCase naming conventions and improve readability Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * Add translations and updates for `must_enter_reference_code` and `reference_code` across language files and update `Sales` controller to replace `must_enter_rrn` with the new key Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * feat(sales): add reference code input and payment type helper - Add `get_reference_code_payment_types()` to locale_helper as single source of truth for card-requiring payment types - Add reference code row to register view, shown/hidden via JS based on selected payment type - Fix payment type dropdown width to 100% for consistent layout - Add min-width to payment buttons and right-padding to button group Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * feat(config): add payment reference code length configuration - Add payment_reference_code_min and payment_reference_code_max fields to Config controller save logic - Add translation keys for reference code length limits across all language files (min/max label + section header) - Align array key formatting in Config controller for readability Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * style(lang): normalize string delimiters to single quotes across all language files Convert double-quoted array keys and values to single quotes in all app/Language/*/Config.php and app/Language/*/Sales.php variants. No translation content changed — formatting only. Also add Localization section to AGENTS.md documenting language file conventions for new keys and fallback behavior. Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * feat(lang): add payment reference code length translations Add localized strings for payment_reference_code_length_limits, payment_reference_code_length_max_label, and payment_reference_code_length_min_label across all supported locales. Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * test(config,sales): add payment reference code min/max validation tests - Add baseLocalePayload() helper in ConfigTest for postSaveLocale tests - Add testSaveLocale_AcceptsValidReferenceCodeMinMax and related boundary tests - Add Sale_libPaymentTest for payment reference code validation in Sale_lib Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * fix(sales): add type-specific validation for amount_tendered Gift card payments use amount_tendered as giftcard number (integer); cash/other payments require decimal_locale format. Apply correct validation rule per payment type instead of generic required. Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * fix(lang): replace self-closing </br> with <br> in all locales Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * fix(sales): use configurable precision in discount comparison Replace hardcoded precision 2 with totals_decimals() when comparing discount against item total via bccomp/bcmul, so discount validation respects the configured decimal precision setting. Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * fix(lang): correct Azerbaijani translations in Config.php Replace placeholder/mismatched strings with accurate translations: - email_mailpath, email_smtp_pass, invoice_email_message - number_locale_invalid/required, receipt_template - reward_configuration, right, tax_decimals, theme Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * feat(sales): add reference code support to payment edit flow - Add reference_code field to new payment row in sale edit form - Persist reference_code on insert in Sale model - Validate reference_code_new in Sales controller using configurable min/max length rules Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * feat(lang): add Georgian (ka) language stubs for Config and Sales Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * Match the fallback maximum reference_code length to the maximum of the field in the db Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> * Bug fixes - Add validation of UI settings to prevent overridden values from being passed. - Correct maximum value in JS for payment_reference_code maximum length to 40. - Fix bug causing copy_entire_sale() to incorrectly copy the reference code and cash_adjustment Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> --------- Signed-off-by: Travis Garrison <travis@chiraqbookstore.com> Co-authored-by: Travis Garrison <travis@chiraqbookstore.com>
403 lines
19 KiB
PHP
403 lines
19 KiB
PHP
<?php
|
|
/**
|
|
* @var string $currency_code
|
|
* @var array $rounding_options
|
|
* @var string $controller_name
|
|
* @var array $config
|
|
*/
|
|
?>
|
|
|
|
<?= form_open('config/saveLocale/', ['id' => 'locale_config_form', 'class' => 'form-horizontal']) ?>
|
|
<div id="config_wrapper">
|
|
<fieldset id="config_info">
|
|
|
|
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
|
|
<ul id="locale_error_message_box" class="error_message_box"></ul>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.number_locale'), 'number_locale', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-1">
|
|
<?= form_input([
|
|
'name' => 'number_locale',
|
|
'id' => 'number_locale',
|
|
'class' => 'form-control input-sm',
|
|
'value' => $config['number_locale']
|
|
]) ?>
|
|
<?= form_hidden(['name' => 'save_number_locale', 'value' => $config['number_locale']]) ?>
|
|
</div>
|
|
<div class="col-xs-2">
|
|
<label class="control-label">
|
|
<a href="https://github.com/opensourcepos/opensourcepos/wiki/Localisation-support" target="_blank">
|
|
<span class="glyphicon glyphicon-info-sign" data-toggle="tooltip" data-placement="right" title="<?= lang('Config.number_locale_tooltip') ?>"></span>
|
|
</a>
|
|
<span id="number_locale_example">
|
|
<?= to_currency(1234567890.12300) ?>
|
|
</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.thousands_separator'), 'thousands_separator', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-2">
|
|
<?= form_checkbox([
|
|
'name' => 'thousands_separator',
|
|
'id' => 'thousands_separator',
|
|
'value' => 'thousands_separator',
|
|
'checked' => $config['thousands_separator'] == 1
|
|
]) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.currency_symbol'), 'currency_symbol', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-1">
|
|
<?= form_input([
|
|
'name' => 'currency_symbol',
|
|
'id' => 'currency_symbol',
|
|
'class' => 'form-control input-sm number_locale',
|
|
'value' => $config['currency_symbol']
|
|
]) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.currency_code'), 'currency_code', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-1">
|
|
<?= form_input([
|
|
'name' => 'currency_code',
|
|
'id' => 'currency_code',
|
|
'class' => 'form-control input-sm number_locale',
|
|
'value' => $currency_code
|
|
]) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.currency_decimals'), 'currency_decimals', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-2">
|
|
<?= form_dropdown(
|
|
'currency_decimals',
|
|
[
|
|
'0' => '0',
|
|
'1' => '1',
|
|
'2' => '2'
|
|
],
|
|
$config['currency_decimals'],
|
|
['class' => 'form-control input-sm']
|
|
) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.tax_decimals'), 'tax_decimals', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-2">
|
|
<?= form_dropdown(
|
|
'tax_decimals',
|
|
[
|
|
'0' => '0',
|
|
'1' => '1',
|
|
'2' => '2',
|
|
'3' => '3',
|
|
'4' => '4'
|
|
],
|
|
$config['tax_decimals'],
|
|
['class' => 'form-control input-sm']
|
|
) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.quantity_decimals'), 'quantity_decimals', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-2">
|
|
<?= form_dropdown(
|
|
'quantity_decimals',
|
|
[
|
|
'0' => '0',
|
|
'1' => '1',
|
|
'2' => '2',
|
|
'3' => '3'
|
|
],
|
|
$config['quantity_decimals'],
|
|
['class' => 'form-control input-sm']
|
|
) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.cash_decimals'), 'cash_decimals', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-2">
|
|
<?= form_dropdown(
|
|
'cash_decimals',
|
|
[
|
|
'-1' => '-1',
|
|
'0' => '0',
|
|
'1' => '1',
|
|
'2' => '2'
|
|
],
|
|
$config['cash_decimals'],
|
|
['class' => 'form-control input-sm']
|
|
) ?>
|
|
</div>
|
|
<div class="col-xs-1">
|
|
<label class="control-label">
|
|
<span class="glyphicon glyphicon-info-sign" data-toggle="tooltip" data-placement="right" title="<?= lang('Config.cash_decimals_tooltip') ?>"></span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.cash_rounding'), 'cash_rounding_code', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-2">
|
|
<?= form_dropdown(
|
|
'cash_rounding_code',
|
|
$rounding_options,
|
|
$config['cash_rounding_code'],
|
|
'class="form-control input-sm"'
|
|
) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.payment_options_order'), 'payment_options_order', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-4">
|
|
<?= form_dropdown(
|
|
'payment_options_order',
|
|
[
|
|
'cashdebitcredit' => lang('Sales.cash') . ' / ' . lang('Sales.debit') . ' / ' . lang('Sales.credit'),
|
|
'debitcreditcash' => lang('Sales.debit') . ' / ' . lang('Sales.credit') . ' / ' . lang('Sales.cash'),
|
|
'debitcashcredit' => lang('Sales.debit') . ' / ' . lang('Sales.cash') . ' / ' . lang('Sales.credit'),
|
|
'creditdebitcash' => lang('Sales.credit') . ' / ' . lang('Sales.debit') . ' / ' . lang('Sales.cash'),
|
|
'creditcashdebit' => lang('Sales.credit') . ' / ' . lang('Sales.cash') . ' / ' . lang('Sales.debit')
|
|
],
|
|
$config['payment_options_order'],
|
|
'class="form-control input-sm"'
|
|
) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm" style="display:flex; align-items:center">
|
|
<?= form_label(lang('Config.payment_reference_code_length_limits'), 'payment_reference_code_length', ['class' => 'control-label col-xs-2', 'style' => 'padding-top:0; line-height:1.4; margin-top:-8px']) ?>
|
|
<div class="col-xs-4">
|
|
<div id="payment_reference_code_slider"></div>
|
|
<div class="row" style="margin-top:6px">
|
|
<div class="col-xs-6">
|
|
<span class="control-label"><?= lang('Config.payment_reference_code_length_min_label') ?>: </span>
|
|
<span id="payment_reference_code_min_display"><?= $config['payment_reference_code_min'] ?? 3 ?></span>
|
|
<?= form_input(['type' => 'hidden', 'name' => 'payment_reference_code_min', 'id' => 'payment_reference_code_min', 'value' => $config['payment_reference_code_min'] ?? 3]) ?>
|
|
</div>
|
|
<div class="col-xs-6">
|
|
<span class="control-label"><?= lang('Config.payment_reference_code_length_max_label') ?>: </span>
|
|
<span id="payment_reference_code_max_display"><?= $config['payment_reference_code_max'] ?? 40 ?></span>
|
|
<?= form_input(['type' => 'hidden', 'name' => 'payment_reference_code_max', 'id' => 'payment_reference_code_max', 'value' => $config['payment_reference_code_max'] ?? 40]) ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.country_codes'), 'country_codes', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-1">
|
|
<?= form_input([
|
|
'name' => 'country_codes',
|
|
'class' => 'form-control input-sm',
|
|
'value' => $config['country_codes']
|
|
]) ?>
|
|
</div>
|
|
<div class="col-xs-1">
|
|
<label class="control-label">
|
|
<a href="https://wiki.openstreetmap.org/wiki/Nominatim/Country_Codes" target="_blank">
|
|
<span class="glyphicon glyphicon-info-sign" data-toggle="tooltip" data-placement="right" title="<?= lang('Config.country_codes_tooltip'); ?>"></span>
|
|
</a>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.language'), 'language', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-4">
|
|
<?= form_dropdown(
|
|
'language',
|
|
get_languages(),
|
|
current_language_code(true) . ':' . current_language(true),
|
|
['class' => 'form-control input-sm']
|
|
) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.timezone'), 'timezone', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-4">
|
|
<?= form_dropdown(
|
|
'timezone',
|
|
get_timezones(),
|
|
$config['timezone'] ? $config['timezone'] : date_default_timezone_get(),
|
|
['class' => 'form-control input-sm']
|
|
) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.datetimeformat'), 'datetimeformat', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-sm-2">
|
|
<?= form_dropdown(
|
|
'dateformat',
|
|
get_dateformats(),
|
|
$config['dateformat'],
|
|
['class' => 'form-control input-sm']
|
|
) ?>
|
|
</div>
|
|
<div class="col-sm-2">
|
|
<?= form_dropdown(
|
|
'timeformat',
|
|
get_timeformats(),
|
|
$config['timeformat'],
|
|
['class' => 'form-control input-sm']
|
|
) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.date_or_time_format'), 'date_or_time_format', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-2">
|
|
<?= form_checkbox([
|
|
'name' => 'date_or_time_format',
|
|
'id' => 'date_or_time_format',
|
|
'value' => 'date_or_time_format',
|
|
'checked' => $config['date_or_time_format'] == 1
|
|
]) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group form-group-sm">
|
|
<?= form_label(lang('Config.financial_year'), 'financial_year', ['class' => 'control-label col-xs-2']) ?>
|
|
<div class="col-xs-2">
|
|
<?= form_dropdown(
|
|
'financial_year',
|
|
[
|
|
'1' => lang('Config.financial_year_jan'),
|
|
'2' => lang('Config.financial_year_feb'),
|
|
'3' => lang('Config.financial_year_mar'),
|
|
'4' => lang('Config.financial_year_apr'),
|
|
'5' => lang('Config.financial_year_may'),
|
|
'6' => lang('Config.financial_year_jun'),
|
|
'7' => lang('Config.financial_year_jul'),
|
|
'8' => lang('Config.financial_year_aug'),
|
|
'9' => lang('Config.financial_year_sep'),
|
|
'10' => lang('Config.financial_year_oct'),
|
|
'11' => lang('Config.financial_year_nov'),
|
|
'12' => lang('Config.financial_year_dec')
|
|
],
|
|
$config['financial_year'],
|
|
['class' => 'form-control input-sm']
|
|
) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<?= form_submit([
|
|
'name' => 'submit_locale',
|
|
'id' => 'submit_locale',
|
|
'value' => lang('Common.submit'),
|
|
'class' => 'btn btn-primary btn-sm pull-right'
|
|
]) ?>
|
|
|
|
</fieldset>
|
|
</div>
|
|
<?= form_close() ?>
|
|
|
|
<script type="text/javascript">
|
|
// Validation and submit handling
|
|
$(document).ready(function() {
|
|
$('span').tooltip();
|
|
|
|
var primaryColor = $('.btn-primary').css('background-color');
|
|
$('<style>').text(
|
|
'#payment_reference_code_slider .ui-slider-range { background: ' + primaryColor + '; }' +
|
|
'#payment_reference_code_slider .ui-slider-handle { border-color: ' + primaryColor + '; }'
|
|
).appendTo('head');
|
|
|
|
$('#payment_reference_code_slider').slider({
|
|
range: true,
|
|
min: 3,
|
|
max: 40,
|
|
step: 1,
|
|
values: [
|
|
parseInt($('#payment_reference_code_min').val()),
|
|
parseInt($('#payment_reference_code_max').val())
|
|
],
|
|
slide: function(event, ui) {
|
|
$('#payment_reference_code_min').val(ui.values[0]);
|
|
$('#payment_reference_code_max').val(ui.values[1]);
|
|
$('#payment_reference_code_min_display').text(ui.values[0]);
|
|
$('#payment_reference_code_max_display').text(ui.values[1]);
|
|
}
|
|
});
|
|
|
|
$('#currency_symbol, #thousands_separator, #currency_code').change(function() {
|
|
var data = {
|
|
number_locale: $('#number_locale').val()
|
|
};
|
|
data['save_number_locale'] = $("input[name='save_number_locale']").val();
|
|
data['currency_symbol'] = $('#currency_symbol').val();
|
|
data['currency_code'] = $('#currency_code').val();
|
|
data['thousands_separator'] = $('#thousands_separator').is(":checked")
|
|
$.post("<?= "$controller_name/checkNumberLocale" ?>",
|
|
data,
|
|
function(response) {
|
|
$("input[name='save_number_locale']").val(response.save_number_locale);
|
|
$('#number_locale_example').text(response.number_locale_example);
|
|
$('#currency_symbol').val(response.currency_symbol);
|
|
$('#currency_code').val(response.currency_code);
|
|
},
|
|
'json'
|
|
);
|
|
});
|
|
|
|
$('#locale_config_form').validate($.extend(form_support.handler, {
|
|
rules: {
|
|
number_locale: {
|
|
required: true,
|
|
remote: {
|
|
url: "<?= "$controller_name/checkNumberLocale" ?>",
|
|
type: 'POST',
|
|
data: {
|
|
'number_locale': function() {
|
|
return $('#number_locale').val();
|
|
},
|
|
'save_number_locale': function() {
|
|
return $("input[name='save_number_locale']").val();
|
|
},
|
|
'currency_symbol': function() {
|
|
return $('#currency_symbol').val();
|
|
},
|
|
'thousands_separator': function() {
|
|
return $('#thousands_separator').is(':checked');
|
|
},
|
|
'currency_code': function() {
|
|
return $('#currency_code').val();
|
|
}
|
|
},
|
|
dataFilter: function(data) {
|
|
var response = JSON.parse(data);
|
|
$("input[name='save_number_locale']").val(response.save_number_locale);
|
|
$('#number_locale_example').text(response.number_locale_example);
|
|
$('#currency_symbol').val(response.currency_symbol);
|
|
$('#currency_code').val(response.currency_code);
|
|
return response.success;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
messages: {
|
|
number_locale: {
|
|
required: "<?= lang('Config.number_locale_required') ?>",
|
|
number_locale: "<?= lang('Config.number_locale_invalid') ?>"
|
|
}
|
|
},
|
|
|
|
errorLabelContainer: '#locale_error_message_box'
|
|
}));
|
|
});
|
|
</script>
|