Bugfix tax names (#4677)

bugfix(items, validation): reject unsafe tax names and fix payments temp table collision

- Add unicode_alpha_numeric_punct rule (OSPOSRules) to allow accented/CJK
  chars in text fields while blocking HTML-unsafe chars (<, >) as
  defense-in-depth against injection
- Items controller: extract validateItemFields/validateBulkUpdateFields,
  validate tax_names on save and bulk update using new rule; add shared
  validateFields helper in Secure_Controller to DRY up validation +
  JSON error response
- Escape tax_group output in sales/quote.php and receipt_email.php views
  to harden output encoding at render time
- Rename sales_payments_temp -> sales_report_payments_temp (Summary_report)
  and -> sales_search_payments_temp (Sale model) to avoid name collision
  between concurrently-created temp tables
- AGENTS.md: document alignment rule for => columns when inserting new
  language keys

Tests:
- Add ItemsControllerTest covering postSave/bulkupdate tax_names validation
- Reject <, > in tax_names on /items/save and /items/bulkupdate
- Verify unicode and apostrophe-containing tax names are accepted
- Cover CSV import helpers: header generation (basic, multiple locations,
  attributes), stock-location/attribute header builders, get_csv_file
  parsing (plain, BOM-prefixed, multi-row)
- Validate required-header detection for import templates
- Remove outdated tax name test from SalesControllerTest
- Simplify Database class references in SalesControllerTest

i18n:
- Add tax_name_invalid translation to Items.php for 20+ locales, inserted
  alphabetically after tax_category in each file
- Normalize quote style in ar-EG/Items.php to single quotes
- Add ka/Items.php Georgian locale scaffold

Signed-off-by: objecttothis <17935339+objecttothis@users.noreply.github.com>
This commit is contained in:
objecttothis authored and GitHub committed 2026-09-01 10:59:29 +04:00
1 parent 905a447e55
commit 6db3dde491
58 files changed
+5777 -5334

No files matched your search

+27 -6
View File
@@ -2,13 +2,13 @@
namespace Tests\Controllers;
use CodeIgniter\Database\Config;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\DatabaseTestTrait;
use CodeIgniter\Test\FeatureTestTrait;
use CodeIgniter\Config\Services;
use App\Database\Seeds\TestDatabaseBootstrapSeeder;
use App\Models\Employee;
use Config\OSPOS;
use Config\Database;
use Tests\Support\ItemFixtureTrait;
/**
@@ -36,14 +36,13 @@ class SalesControllerTest extends CIUnitTestCase
protected function setUp(): void
{
if (self::$doneBootstrap === false) {
TestDatabaseBootstrapSeeder::reset();
Config::seeder($this->DBGroup)->call('App\Database\Seeds\TestDatabaseBootstrapSeeder');
Config::connect($this->DBGroup)->close();
self::$doneBootstrap = true;
}
parent::setUp();
config(OSPOS::class)->update_settings();
}
protected function tearDown(): void
@@ -224,7 +223,7 @@ class SalesControllerTest extends CIUnitTestCase
protected function createSale(int $employeeId): int
{
$unique = uniqid();
$db = \Config\Database::connect();
$db = Database::connect();
$db->table('items')->insert([
'name' => "Test Item $unique",
@@ -519,4 +518,26 @@ class SalesControllerTest extends CIUnitTestCase
$cart = $session->get('sales_cart');
$this->assertEquals('0.01', $cart[1]['price']);
}
public function testRegisterEscapesMaliciousTaxName(): void
{
$cashierId = $this->createCashierEmployee();
$itemId = $this->createTestItem();
Database::connect()->table('items_taxes')->insert([
'item_id' => $itemId,
'name' => '<svg onload=alert(1)>',
'percent' => 5,
]);
$this->loginAs($cashierId);
$this->seedCartLine(1, '5.00', $itemId);
$response = $this->get('/sales');
$response->assertStatus(200);
$body = $response->getBody();
$this->assertStringNotContainsString('<svg onload', $body);
$this->assertStringContainsString('&lt;svg', $body);
}
}