Files
opensourcepos/tests/helpers/GetItemDataRowTest.php
T
objecttothisandOllama 1b8ee2e3c1 feat(items): optimize search, attribute filtering, and sort for items view (#4652)
feat(items): optimize search, attribute filtering, and sort for items view (#4652)

BREAKING CHANGE: none

## Search & Query Optimization
- Split item search into two-phase query: Phase A resolves qualifying IDs,
  Phase B joins scoped display tables for better performance and readability
- Sanitize `definition_ids` via `array_map` to prevent injection vulnerabilities
- Introduce subquery for SUM aggregation to prevent over-counting across joins
- Add validation requiring both start and end dates before applying date range filter

## Attribute Search (fixes #2919, #2722)
- Add `SHOW_IN_SEARCH` flag (value 8) to Attribute model to separate
  searchability from table visibility
- Add `parse_attribute_search()` to parse syntax like `color:blue AND size:large`
- Add `applyNamedAttributeSearch()` supporting decimal and date types with
  locale-aware parsing
- Support AND/OR logic for multi-attribute queries

## Sorting
- Add `get_attribute_sort_definition_id()` to detect attribute column sorting
- Join attribute tables dynamically when sorting by attribute columns
- Use `MAX()` for consistent results when sorting by attribute values
- Replace static sort column list with dynamic headers via `itemSortColumns()`
- Add `sanitizeSortColumnAttribute()` to validate attribute definition IDs as sort columns

## Tax & Data Row
- Streamline tax computation in `getItemDataRow()`

## Low Inventory Filter
- Require valid `stock_location_id` before applying low inventory filter
- Add conditional logic to sort by sum of quantities across all locations
  when `stock_location_id` is invalid

## Localization
- Add `show_in_search` / `show_in_search_visibility` strings to all language files
- Translated: de-DE, es-ES, fr, it; English placeholder for remaining locales
- Unify single-quote style across all attribute language files

## Refactoring & Style
- Adopt camelCase naming throughout (variables, helpers, methods)
- Replace `sanitizeSortColumnAttribute` with reusable `sanitizeSortColumn`
  from `Secure_Controller`
- Simplify column key extraction using `array_key_first`
- Apply PSR-12 formatting

## Tests
- Add tests for tax computation, quantity aggregation (single- and multi-location),
  named attribute search, free-text parsing, and date/decimal type handling
- Add `ensureStockLocation` helper to auto-create missing stock locations in tests
- Refactor tests to handle config cache issues

Co-authored-by: Ollama <ollama@steganos.dev>
2026-10-02 14:56:20 +04:00

108 lines
3.0 KiB
PHP

<?php
namespace Tests\Helpers;
use CodeIgniter\Config\Factories;
use CodeIgniter\Test\CIUnitTestCase;
use Config\OSPOS;
use stdClass;
class GetItemDataRowTest extends CIUnitTestCase
{
protected function setUp(): void
{
parent::setUp();
helper('tabular');
$this->injectSettings();
}
protected function injectSettings(array $overrides = []): void
{
$config = new OSPOS();
$config->settings = array_merge([
'multi_pack_enabled' => 0,
'use_destination_based_tax' => 0,
'number_locale' => 'en_US',
'currency_decimals' => 2,
'quantity_decimals' => 0,
'thousands_separator' => 1,
'currency_symbol' => '$',
], $overrides);
Factories::injectMock('config', OSPOS::class, $config);
}
protected function makeItem(array $overrides = []): stdClass
{
$item = new stdClass();
$defaults = [
'item_id' => 1,
'item_number' => 'ITEM-001',
'name' => 'Test Item',
'category' => 'Test Category',
'company_name' => 'Test Supplier',
'cost_price' => 10.00,
'unit_price' => 20.00,
'quantity' => 5,
'pic_filename' => null,
'pack_name' => null,
'tax_category_id' => null,
];
foreach (array_merge($defaults, $overrides) as $key => $value) {
$item->$key = $value;
}
return $item;
}
public function testTaxPercentsPulledFromPassedMapNotQueried(): void
{
$item = $this->makeItem(['item_id' => 42]);
$columns = getItemDataRow($item, [], [42 => '20.00%']);
$this->assertEquals('20.00%', $columns['tax_percents']);
}
public function testTaxPercentsDefaultsToDashWhenItemIdMissingFromMap(): void
{
$item = $this->makeItem(['item_id' => 99]);
$columns = getItemDataRow($item, [], []);
$this->assertEquals('-', $columns['tax_percents']);
}
public function testDefinitionNamesPassedThroughToExpandAttributeValues(): void
{
$item = $this->makeItem(['item_id' => 7]);
$item->attribute_values = '3_Red';
$item->attribute_dtvalues = '';
$item->attribute_dvalues = '';
$definitionNames = [
3 => ['name' => 'Color', 'type' => TEXT],
];
$columns = getItemDataRow($item, $definitionNames, []);
$this->assertArrayHasKey(3, $columns);
$this->assertEquals('Red', $columns[3]);
}
public function testPackNameAppendedToItemName(): void
{
$this->injectSettings(['multi_pack_enabled' => 1]);
$item = $this->makeItem(['name' => 'Base Item', 'pack_name' => 'Pack of 6']);
$columns = getItemDataRow($item, [], []);
$this->assertEquals('Base Item' . NAME_SEPARATOR . 'Pack of 6', $columns['name']);
}
}