Compare commits

..

1 Commits

Author SHA1 Message Date
jekkos
09191b9af7 feat: Add OpenAPI 3.1 specification for REST API
Add comprehensive OpenAPI specification for OSPOS REST API including:

- Customers API (CRUD operations)
- Suppliers API (CRUD operations)
- Items API (CRUD operations with inventory quantities)
- Inventory API (stock adjustments)
- Sales API (read-only queries)
- Receivings API (read-only queries)

Features:
- API Key authentication via X-API-Key header
- Pagination with offset/limit parameters
- Soft delete support for customers, suppliers, items
- Batch operations for delete and update
- Search/suggest endpoints for autocomplete
- Comprehensive schema definitions based on existing models

Includes documentation with:
- Endpoint reference tables
- Schema field descriptions
- Implementation notes and discussion topics
- HTTP status codes and response formats

This is a design proposal for discussion before implementation.
2026-03-06 10:27:11 +00:00
129 changed files with 2566 additions and 3075 deletions

View File

@@ -111,15 +111,7 @@ jobs:
env:
CI_ENVIRONMENT: testing
MYSQL_HOST_NAME: 127.0.0.1
run: composer test -- --log-junit test-results/junit.xml
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results-php-${{ matrix.php-version }}
path: test-results/
retention-days: 30
run: composer test
- name: Stop MariaDB
if: always()

295
API.md Normal file
View File

@@ -0,0 +1,295 @@
# OSPOS REST API Design
This document describes the proposed REST API for Open Source Point of Sale (OSPOS).
## Overview
The OSPOS REST API provides programmatic access to:
- **Customers** - Full CRUD operations
- **Suppliers** - Full CRUD operations
- **Items** - Full CRUD operations
- **Inventory** - Stock adjustments (update only)
- **Sales** - Read-only queries
- **Receivings** - Read-only queries
## Authentication
All API endpoints require authentication via an API Key passed in the `X-API-Key` header.
```
X-API-Key: your-api-key-here
```
> **Note:** API Key authentication implementation will be added in a subsequent phase. The spec documents the intended authentication mechanism.
## Base URL
All API endpoints are relative to `/api/v1`.
```
https://your-domain.com/api/v1/customers
```
## Pagination
List endpoints support pagination using `offset` and `limit` query parameters:
| Parameter | Type | Default | Maximum | Description |
|-----------|---------|---------|---------|------------------------------|
| `offset` | integer | 0 | - | Number of records to skip |
| `limit` | integer | 25 | 100 | Number of records to return |
**Example Request:**
```
GET /api/v1/customers?offset=0&limit=25
```
**Example Response:**
```json
{
"total": 150,
"offset": 0,
"limit": 25,
"rows": [
{ "person_id": 1, "first_name": "John", ... },
{ "person_id": 2, "first_name": "Jane", ... }
]
}
```
## Response Format
### Success Response
```json
{
"success": true,
"message": "Customer created successfully",
"id": 42
}
```
### Error Response
```json
{
"success": false,
"message": "Error description here"
}
```
### HTTP Status Codes
| Status Code | Description |
|-------------|--------------------------------------------------|
| 200 | Success |
| 201 | Resource created successfully |
| 400 | Bad request / Invalid input |
| 401 | Unauthorized / Invalid API key |
| 404 | Resource not found |
| 409 | Conflict (e.g., duplicate unique field) |
| 500 | Internal server error |
## Endpoints Summary
### Customers
| Method | Endpoint | Description | Access |
|--------|-------------------------------|--------------------------------|---------|
| GET | `/customers` | List customers | Read |
| POST | `/customers` | Create customer | Write |
| GET | `/customers/{id}` | Get customer by ID | Read |
| PUT | `/customers/{id}` | Update customer | Write |
| DELETE | `/customers/{id}` | Delete customer (soft delete) | Write |
| POST | `/customers/batch-delete` | Delete multiple customers | Write |
| GET | `/customers/suggest` | Autocomplete suggestions | Read |
### Suppliers
| Method | Endpoint | Description | Access |
|--------|-------------------------------|--------------------------------|---------|
| GET | `/suppliers` | List suppliers | Read |
| POST | `/suppliers` | Create supplier | Write |
| GET | `/suppliers/{id}` | Get supplier by ID | Read |
| PUT | `/suppliers/{id}` | Update supplier | Write |
| DELETE | `/suppliers/{id}` | Delete supplier (soft delete) | Write |
| POST | `/suppliers/batch-delete` | Delete multiple suppliers | Write |
| GET | `/suppliers/suggest` | Autocomplete suggestions | Read |
### Items
| Method | Endpoint | Description | Access |
|--------|-------------------------------|--------------------------------|---------|
| GET | `/items` | List items | Read |
| POST | `/items` | Create item | Write |
| GET | `/items/{id}` | Get item by ID | Read |
| PUT | `/items/{id}` | Update item | Write |
| DELETE | `/items/{id}` | Delete item (soft delete) | Write |
| POST | `/items/batch-delete` | Delete multiple items | Write |
| POST | `/items/batch-update` | Update multiple items | Write |
| GET | `/items/suggest` | Autocomplete suggestions | Read |
| GET | `/items/{id}/quantities` | Get stock quantities | Read |
### Inventory
| Method | Endpoint | Description | Access |
|--------|-------------------------------|--------------------------------|---------|
| GET | `/inventory` | List inventory transactions | Read |
| POST | `/inventory` | Create inventory adjustment | Write |
| POST | `/inventory/bulk` | Bulk inventory adjustments | Write |
### Sales (Read-Only)
| Method | Endpoint | Description | Access |
|--------|-------------------------------|--------------------------------|---------|
| GET | `/sales` | List sales | Read |
| GET | `/sales/{id}` | Get sale details | Read |
| GET | `/sales/{id}/items` | Get sale items | Read |
| GET | `/sales/{id}/payments` | Get sale payments | Read |
### Receivings (Read-Only)
| Method | Endpoint | Description | Access |
|--------|-------------------------------|--------------------------------|---------|
| GET | `/receivings` | List receivings | Read |
| GET | `/receivings/{id}` | Get receiving details | Read |
| GET | `/receivings/{id}/items` | Get receiving items | Read |
## Schema Reference
### Common Fields
#### Person Fields (base for Customer, Supplier)
| Field | Type | Description |
|---------------|-----------|------------------------------|
| `first_name` | string | First name (required) |
| `last_name` | string | Last name (required) |
| `gender` | integer | Gender (0=male, 1=female) |
| `phone_number`| string | Phone number |
| `email` | string | Email address |
| `address_1` | string | Address line 1 |
| `address_2` | string | Address line 2 |
| `city` | string | City |
| `state` | string | State/Province |
| `zip` | string | Postal/ZIP code |
| `country` | string | Country |
| `comments` | string | Additional notes |
### Customer Fields
Extends Person fields with:
| Field | Type | Description |
|--------------------|-----------|------------------------------------|
| `person_id` | integer | Unique identifier (read-only) |
| `account_number` | string | Customer account number |
| `taxable` | integer | Taxable status (0/1) |
| `tax_id` | string | Tax identification number |
| `sales_tax_code_id`| integer | Sales tax code ID |
| `discount` | decimal | Discount percentage/amount |
| `discount_type` | integer | Discount type (0=percent, 1=fixed) |
| `company_name` | string | Company name |
| `package_id` | integer | Rewards package ID |
| `points` | integer | Rewards points balance |
| `consent` | integer | Consent status (0/1) |
### Supplier Fields
Extends Person fields with:
| Field | Type | Description |
|-----------------|-----------|-------------------------------------|
| `person_id` | integer | Unique identifier (read-only) |
| `company_name` | string | Company name |
| `account_number`| string | Supplier account number |
| `tax_id` | string | Tax identification number |
| `agency_name` | string | Agency name |
| `category` | integer | Category (0=goods, 1=cost) |
### Item Fields
| Field | Type | Required | Description |
|----------------------|-----------|----------|--------------------------------------|
| `item_id` | integer | auto | Unique identifier (read-only) |
| `name` | string | yes | Item name |
| `category` | string | yes | Item category |
| `supplier_id` | integer | no | Supplier ID |
| `item_number` | string | no | Barcode/SKU |
| `description` | string | no | Item description |
| `cost_price` | decimal | no | Cost price |
| `unit_price` | decimal | yes | Selling price |
| `reorder_level` | decimal | no | Reorder threshold |
| `receiving_quantity` | decimal | no | Receiving quantity (default 1) |
| `allow_alt_description`| integer | no | Allow alt description (0/1) |
| `is_serialized` | integer | no | Has serial number (0/1) |
| `stock_type` | integer | no | Stock type (0=stocked, 1=non-stocked)|
| `item_type` | integer | no | Item type (0=standard, 1=kit, 2=temp)|
| `tax_category_id` | integer | no | Tax category ID |
| `qty_per_pack` | decimal | no | Quantity per pack |
| `pack_name` | string | no | Pack name |
| `hsn_code` | string | no | HSN code |
### Inventory Adjustment
| Field | Type | Required | Description |
|------------------|-----------|----------|--------------------------------------|
| `item_id` | integer | yes | Item ID to adjust |
| `trans_inventory`| decimal | yes | Quantity change (+ add, - remove) |
| `trans_location` | integer | no | Stock location ID |
| `trans_comment` | string | no | Reason for adjustment |
## OpenAPI Specification
The complete OpenAPI 3.1.0 specification is available at:
- **YAML format:** `/public/api/openapi.yaml`
This specification can be used with:
- [Swagger UI](https://swagger.io/tools/swagger-ui/) for interactive documentation
- [Swagger Codegen](https://swagger.io/tools/swagger-codegen/) to generate client SDKs
- [OpenAPI Generator](https://openapi-generator.tech/) for code generation
- API testing tools like Postman or Insomnia
## Implementation Notes
### Phase 1: Core Endpoints (Proposed)
1. Customers API (full CRUD)
2. Suppliers API (full CRUD)
3. Items API (full CRUD)
4. Inventory adjustments API (create only)
### Phase 2: Read-Only Endpoints (Proposed)
1. Sales API (read-only)
2. Receivings API (read-only)
### Phase 3: Extended Features (Future)
1. Batch operations for all endpoints
2. Search/filter capabilities
3. Authorization/permissions integration
4. Rate limiting
5. API key management interface
## Discussion Topics
The following aspects of the API design are open for discussion:
1. **Field naming conventions**: Currently following existing database column names. Should we use camelCase for JSON?
2. **Batch operations**: Current design separates batch-delete and batch-update. Should we consolidate?
3. **Date formats**: Using ISO 8601 (date-time). Is timezone handling needed?
4. **Error response structure**: Current format uses `{success, message}`. Should we include error codes?
5. **Relationship representations**: Should nested resources (e.g., sale items) always be included?
6. **Inventory adjustments**: Should we support setting absolute quantities vs. relative changes?
7. **Authorization integration**: How should API access integrate with existing employee permissions?
8. **Stock locations**: Multiple locations per item - do we need location-specific endpoints?

View File

@@ -205,7 +205,6 @@ class Autoload extends AutoloadConfig
'cookie',
'tabular',
'locale',
'security',
'plugin'
'security'
];
}

View File

@@ -169,8 +169,3 @@ const MAX_PRECISION = 1e14;
const DEFAULT_PRECISION = 2;
const DEFAULT_LANGUAGE = 'english';
const DEFAULT_LANGUAGE_CODE = 'en';
/**
* Admin modules - list of modules required for admin privileges
*/
const ADMIN_MODULES = ['customers', 'employees', 'giftcards', 'items', 'item_kits', 'messages', 'receivings', 'reports', 'sales', 'config', 'suppliers'];

View File

@@ -8,7 +8,23 @@ use CodeIgniter\HotReloader\HotReloader;
use App\Events\Db_log;
use App\Events\Load_config;
use App\Events\Method;
use App\Libraries\Plugins\PluginManager;
/*
* --------------------------------------------------------------------
* Application Events
* --------------------------------------------------------------------
* Events allow you to tap into the execution of the program without
* modifying or extending core files. This file provides a central
* location to define your events, though they can always be added
* at run-time, also, if needed.
*
* You create code that can execute by subscribing to events with
* the 'on()' method. This accepts any form of callable, including
* Closures, that will be executed when the event is triggered.
*
* Example:
* Events::on('create', [$myInstance, 'myMethod']);
*/
Events::on('pre_system', static function (): void {
if (ENVIRONMENT !== 'testing') {
@@ -23,19 +39,22 @@ Events::on('pre_system', static function (): void {
ob_start(static fn ($buffer) => $buffer);
}
/*
* --------------------------------------------------------------------
* Debug Toolbar Listeners.
* --------------------------------------------------------------------
* If you delete, they will no longer be collected.
*/
if (CI_DEBUG && ! is_cli()) {
Events::on('DBQuery', 'CodeIgniter\Debug\Toolbar\Collectors\Database::collect');
service('toolbar')->respond();
// Hot Reload route - for framework use on the hot reloader.
if (ENVIRONMENT === 'development') {
service('routes')->get('__hot-reload', static function (): void {
(new HotReloader())->run();
});
}
}
$pluginManager = new PluginManager();
$pluginManager->discoverPlugins();
$pluginManager->registerPluginEvents();
});
$config = new Load_config();
@@ -45,4 +64,4 @@ $db_log = new Db_log();
Events::on('DBQuery', [$db_log, 'db_log_queries']);
$method = new Method();
Events::on('pre_controller', [$method, 'validate_method']);
Events::on('pre_controller', [$method, 'validate_method']);

View File

@@ -461,9 +461,8 @@ class Config extends Secure_Controller
public function postSaveLocale(): ResponseInterface
{
$exploded = explode(":", $this->request->getPost('language'));
$currency_symbol = $this->request->getPost('currency_symbol');
$batch_save_data = [
'currency_symbol' => htmlspecialchars($currency_symbol ?? ''),
'currency_symbol' => $this->request->getPost('currency_symbol'),
'currency_code' => $this->request->getPost('currency_code'),
'language_code' => $exploded[0],
'language' => $exploded[1],
@@ -943,9 +942,7 @@ class Config extends Secure_Controller
'work_order_enable' => $this->request->getPost('work_order_enable') != null,
'work_order_format' => $this->request->getPost('work_order_format'),
'last_used_work_order_number' => $this->request->getPost('last_used_work_order_number', FILTER_SANITIZE_NUMBER_INT),
'invoice_type' => Sale_lib::isValidInvoiceType($this->request->getPost('invoice_type'))
? $this->request->getPost('invoice_type')
: 'invoice'
'invoice_type' => $this->request->getPost('invoice_type')
];
$success = $this->appconfig->batch_save($batch_save_data);

View File

@@ -78,7 +78,7 @@ class Employees extends Persons
$person_info = $this->employee->get_info($employee_id);
$current_user = $this->employee->get_logged_in_employee_info();
if ($employee_id != NEW_ENTRY && !$this->employee->canModifyEmployee($person_info->person_id, $current_user->person_id)) {
if ($employee_id != NEW_ENTRY && !$this->employee->can_modify_employee($person_info->person_id, $current_user->person_id)) {
header('Location: ' . base_url('no_access/employees/employees'));
exit();
}
@@ -120,7 +120,7 @@ class Employees extends Persons
if ($employee_id != NEW_ENTRY) {
$target_employee = $this->employee->get_info($employee_id);
if (!$this->employee->canModifyEmployee($target_employee->person_id, $current_user->person_id)) {
if (!$this->employee->can_modify_employee($target_employee->person_id, $current_user->person_id)) {
return $this->response->setJSON([
'success' => false,
'message' => lang('Employees.error_updating_admin'),
@@ -153,14 +153,14 @@ class Employees extends Persons
];
$grants_array = [];
$isAdmin = $this->employee->isAdmin($current_user->person_id);
$is_admin = $this->employee->is_admin($current_user->person_id);
foreach ($this->module->get_all_permissions()->getResult() as $permission) {
$grants = [];
$grant = $this->request->getPost('grant_' . $permission->permission_id) != null ? $this->request->getPost('grant_' . $permission->permission_id, FILTER_SANITIZE_FULL_SPECIAL_CHARS) : '';
if ($grant == $permission->permission_id) {
if (!$isAdmin && !$this->employee->has_grant($permission->permission_id, $current_user->person_id)) {
if (!$is_admin && !$this->employee->has_grant($permission->permission_id, $current_user->person_id)) {
continue;
}
$grants['permission_id'] = $permission->permission_id;
@@ -226,9 +226,9 @@ class Employees extends Persons
$employees_to_delete = $this->request->getPost('ids', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
$current_user = $this->employee->get_logged_in_employee_info();
if (!$this->employee->isAdmin($current_user->person_id)) {
if (!$this->employee->is_admin($current_user->person_id)) {
foreach ($employees_to_delete as $emp_id) {
if ($this->employee->isAdmin((int)$emp_id)) {
if ($this->employee->is_admin((int)$emp_id)) {
return $this->response->setJSON(['success' => false, 'message' => lang('Employees.error_deleting_admin')]);
}
}

View File

@@ -39,19 +39,9 @@ class Home extends Secure_Controller
* @return string
* @noinspection PhpUnused
*/
public function getChangePassword(int $employeeId = NEW_ENTRY): string
public function getChangePassword(int $employee_id = -1): string // TODO: Replace -1 with a constant
{
$loggedInEmployee = $this->employee->get_logged_in_employee_info();
$currentPersonId = $loggedInEmployee->person_id;
$employeeId = $employeeId === NEW_ENTRY ? $currentPersonId : $employeeId;
if (!$this->employee->can_modify_employee($employeeId, $currentPersonId)) {
header('Location: ' . base_url('no_access/home/home'));
exit();
}
$person_info = $this->employee->get_info($employeeId);
$person_info = $this->employee->get_info($employee_id);
foreach (get_object_vars($person_info) as $property => $value) {
$person_info->$property = $value;
}
@@ -65,20 +55,9 @@ class Home extends Secure_Controller
*
* @return ResponseInterface
*/
public function postSave(int $employeeId = NEW_ENTRY): ResponseInterface
public function postSave(int $employee_id = -1): ResponseInterface // TODO: Replace -1 with a constant
{
$currentUser = $this->employee->get_logged_in_employee_info();
$employeeId = $employeeId === NEW_ENTRY ? $currentUser->person_id : $employeeId;
if (!$this->employee->can_modify_employee($employeeId, $currentUser->person_id)) {
return $this->response->setStatusCode(403)->setJSON([
'success' => false,
'message' => lang('Employees.unauthorized_modify')
]);
}
if (!empty($this->request->getPost('current_password')) && $employeeId != NEW_ENTRY) {
if (!empty($this->request->getPost('current_password')) && $employee_id != -1) {
if ($this->employee->check_password($this->request->getPost('username', FILTER_SANITIZE_FULL_SPECIAL_CHARS), $this->request->getPost('current_password'))) {
// Validate password length BEFORE hashing
$new_password = $this->request->getPost('password');
@@ -87,7 +66,7 @@ class Home extends Secure_Controller
return $this->response->setJSON([
'success' => false,
'message' => lang('Employees.password_minlength'),
'id' => NEW_ENTRY
'id' => -1
]);
}
@@ -97,32 +76,32 @@ class Home extends Secure_Controller
'hash_version' => 2
];
if ($this->employee->change_password($employee_data, $employeeId)) {
if ($this->employee->change_password($employee_data, $employee_id)) {
return $this->response->setJSON([
'success' => true,
'message' => lang('Employees.successful_change_password'),
'id' => $employeeId
'id' => $employee_id
]);
} else {
} else { // Failure // TODO: Replace -1 with constant
return $this->response->setJSON([
'success' => false,
'message' => lang('Employees.unsuccessful_change_password'),
'id' => NEW_ENTRY
'id' => -1
]);
}
} else {
} else { // TODO: Replace -1 with constant
return $this->response->setJSON([
'success' => false,
'message' => lang('Employees.current_password_invalid'),
'id' => NEW_ENTRY
'id' => -1
]);
}
} else {
} else { // TODO: Replace -1 with constant
return $this->response->setJSON([
'success' => false,
'message' => lang('Employees.current_password_invalid'),
'id' => NEW_ENTRY
'id' => -1
]);
}
}
}
}

View File

@@ -96,7 +96,7 @@ class Items extends Secure_Controller
**/
public function getSearch(): ResponseInterface
{
$search = $this->request->getGet('search', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
$search = $this->request->getGet('search');
$limit = $this->request->getGet('limit', FILTER_SANITIZE_NUMBER_INT);
$offset = $this->request->getGet('offset', FILTER_SANITIZE_NUMBER_INT);
$sort = $this->sanitizeSortColumn(item_headers(), $this->request->getGet('sort', FILTER_SANITIZE_FULL_SPECIAL_CHARS), 'item_id');
@@ -148,7 +148,6 @@ class Items extends Secure_Controller
{
helper('file');
$pic_filename = rawurldecode($pic_filename);
$file_extension = pathinfo($pic_filename, PATHINFO_EXTENSION);
$images = glob("./uploads/item_pics/$pic_filename");
$base_path = './uploads/item_pics/' . pathinfo($pic_filename, PATHINFO_FILENAME);
@@ -378,7 +377,7 @@ class Items extends Secure_Controller
} else {
$images = glob("./uploads/item_pics/$item_info->pic_filename");
}
$data['image_path'] = sizeof($images) > 0 ? base_url(implode('/', array_map('rawurlencode', explode('/', ltrim($images[0], './'))))) : '';
$data['image_path'] = sizeof($images) > 0 ? base_url($images[0]) : '';
} else {
$data['image_path'] = '';
}
@@ -618,7 +617,7 @@ class Items extends Secure_Controller
// Save item data
$item_data = [
'name' => $this->request->getPost('name'),
'description' => $this->request->getPost('description', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
'description' => $this->request->getPost('description'),
'category' => $this->request->getPost('category'),
'item_type' => $item_type,
'stock_type' => $this->request->getPost('stock_type') === null ? HAS_STOCK : intval($this->request->getPost('stock_type')),
@@ -769,13 +768,10 @@ class Items extends Secure_Controller
$filename = $file->getClientName();
$info = pathinfo($filename);
// Sanitize filename to remove problematic characters like spaces
$sanitized_name = preg_replace('/[^a-zA-Z0-9_\-\.]/', '_', $info['filename']);
$file_info = [
'orig_name' => $filename,
'raw_name' => $sanitized_name,
'raw_name' => $info['filename'],
'file_ext' => $file->guessExtension()
];
@@ -876,12 +872,12 @@ class Items extends Secure_Controller
$items_to_update = $this->request->getPost('item_ids');
$item_data = [];
foreach (Item::ALLOWED_BULK_EDIT_FIELDS as $field) {
$value = $this->request->getPost($field);
if ($field === 'supplier_id' && $value !== '') {
$item_data[$field] = $value;
} elseif ($value !== null && $value !== '') {
$item_data[$field] = $value;
foreach ($_POST as $key => $value) {
// This field is nullable, so treat it differently
if ($key === 'supplier_id' && $value !== '') {
$item_data[$key] = $value;
} elseif ($value !== '' && !(in_array($key, ['item_ids', 'tax_names', 'tax_percents']))) {
$item_data[$key] = $value;
}
}
@@ -1021,11 +1017,7 @@ class Items extends Secure_Controller
}
if (!$is_failed_row) {
$invalidLocations = $this->validateCSVStockLocations($row, $allowedStockLocations);
if (!empty($invalidLocations)) {
$isFailedRow = true;
log_message('error', 'CSV import: Invalid stock location(s) found: ' . implode(', ', $invalidLocations));
}
$is_failed_row = $this->data_error_check($row, $item_data, $allowed_stock_locations, $attribute_definition_names, $attribute_data);
}
// Remove false, null, '' and empty strings but keep 0
@@ -1071,30 +1063,6 @@ class Items extends Secure_Controller
}
/**
* Validates that stock location columns in CSV row are valid locations
*
* @param array $row
* @param array $allowedLocations
* @return array Returns array of invalid location names, empty if all valid
*/
private function validateCSVStockLocations(array $row, array $allowedLocations): array
{
$invalidLocations = [];
$allowedLocationNames = array_values($allowedLocations);
foreach (array_keys($row) as $key) {
if (str_starts_with($key, 'location_')) {
$locationName = substr($key, 9);
if (!in_array($locationName, $allowedLocationNames)) {
$invalidLocations[] = $locationName;
}
}
}
return $invalidLocations;
}
/**
* Checks the entire line of data in an import file for errors
*

View File

@@ -1,99 +0,0 @@
<?php
namespace App\Controllers\Plugins;
use App\Controllers\Secure_Controller;
use App\Libraries\Plugins\PluginManager;
use CodeIgniter\HTTP\ResponseInterface;
class Manage extends Secure_Controller
{
private PluginManager $pluginManager;
public function __construct()
{
parent::__construct('plugins');
$this->pluginManager = new PluginManager();
$this->pluginManager->discoverPlugins();
}
public function getIndex(): string
{
$plugins = $this->pluginManager->getAllPlugins();
$enabledPlugins = $this->pluginManager->getEnabledPlugins();
$pluginData = [];
foreach ($plugins as $pluginId => $plugin) {
$pluginData[$pluginId] = [
'id' => $plugin->getPluginId(),
'name' => $plugin->getPluginName(),
'description' => $plugin->getPluginDescription(),
'version' => $plugin->getVersion(),
'enabled' => isset($enabledPlugins[$pluginId]),
'has_config' => $plugin->getConfigView() !== null,
];
}
echo view('plugins/manage', ['plugins' => $pluginData]);
return '';
}
public function postEnable(string $pluginId): ResponseInterface
{
if ($this->pluginManager->enablePlugin($pluginId)) {
return $this->response->setJSON(['success' => true, 'message' => lang('Plugins.plugin_enabled')]);
}
return $this->response->setJSON(['success' => false, 'message' => lang('Plugins.plugin_enable_failed')]);
}
public function postDisable(string $pluginId): ResponseInterface
{
if ($this->pluginManager->disablePlugin($pluginId)) {
return $this->response->setJSON(['success' => true, 'message' => lang('Plugins.plugin_disabled')]);
}
return $this->response->setJSON(['success' => false, 'message' => lang('Plugins.plugin_disable_failed')]);
}
public function postUninstall(string $pluginId): ResponseInterface
{
if ($this->pluginManager->uninstallPlugin($pluginId)) {
return $this->response->setJSON(['success' => true, 'message' => lang('Plugins.plugin_uninstalled')]);
}
return $this->response->setJSON(['success' => false, 'message' => lang('Plugins.plugin_uninstall_failed')]);
}
public function getConfig(string $pluginId): ResponseInterface
{
$plugin = $this->pluginManager->getPlugin($pluginId);
if (!$plugin) {
return $this->response->setJSON(['success' => false, 'message' => lang('Plugins.plugin_not_found')]);
}
$configView = $plugin->getConfigView();
if (!$configView) {
return $this->response->setJSON(['success' => false, 'message' => lang('Plugins.plugin_no_config')]);
}
$settings = $plugin->getSettings();
echo view($configView, ['settings' => $settings, 'plugin' => $plugin]);
return $this->response;
}
public function postSaveConfig(string $pluginId): ResponseInterface
{
$plugin = $this->pluginManager->getPlugin($pluginId);
if (!$plugin) {
return $this->response->setJSON(['success' => false, 'message' => lang('Plugins.plugin_not_found')]);
}
$settings = $this->request->getPost();
unset($settings['_method'], $settings['csrf_token_name']);
if ($plugin->saveSettings($settings)) {
return $this->response->setJSON(['success' => true, 'message' => lang('Plugins.settings_saved')]);
}
return $this->response->setJSON(['success' => false, 'message' => lang('Plugins.settings_save_failed')]);
}
}

View File

@@ -755,11 +755,8 @@ class Sales extends Secure_Controller
$data['sale_status'] = COMPLETED;
$sale_type = SALE_TYPE_INVOICE;
$invoice_type = $this->config['invoice_type'];
if (!Sale_lib::isValidInvoiceType($invoice_type)) {
$invoice_type = 'invoice';
}
$invoice_view = $invoice_type;
// The PHP file name is the same as the invoice_type key
$invoice_view = $this->config['invoice_type'];
// Save the data to the sales table
$data['sale_id_num'] = $this->sale->save_value($sale_id, $data['sale_status'], $data['cart'], $customer_id, $employee_id, $data['comments'], $invoice_number, $work_order_number, $quote_number, $sale_type, $data['payments'], $data['dinner_table'], $tax_details);
@@ -1110,9 +1107,6 @@ class Sales extends Secure_Controller
}
$invoice_type = $this->config['invoice_type'];
if (!Sale_lib::isValidInvoiceType($invoice_type)) {
$invoice_type = 'invoice';
}
$data['invoice_view'] = $invoice_type;
return $data;

View File

@@ -267,8 +267,6 @@ class Migration_Sales_Tax_Data extends Migration
*/
public function round_number(int $rounding_mode, string $amount, int $decimals): float
{
$amount = (float)$amount;
if ($rounding_mode == Migration_Sales_Tax_Data::ROUND_UP) {
$fig = pow(10, $decimals);
$rounded_total = (ceil($fig * $amount) + ceil($fig * $amount - ceil($fig * $amount))) / $fig;
@@ -378,7 +376,7 @@ class Migration_Sales_Tax_Data extends Migration
$decimals = totals_decimals();
foreach ($sales_taxes as $row_number => $sales_tax) {
$sale_tax_amount = (float)$sales_tax['sale_tax_amount'];
$sale_tax_amount = $sales_tax['sale_tax_amount'];
$rounding_code = $sales_tax['rounding_code'];
$rounded_sale_tax_amount = $sale_tax_amount;

View File

@@ -243,8 +243,6 @@ class Migration_TaxAmount extends Migration
*/
public function round_number(int $rounding_mode, string $amount, int $decimals): float // TODO: is this currency safe?
{ // TODO: This needs to be converted to a switch
$amount = (float)$amount;
if ($rounding_mode == Migration_TaxAmount::ROUND_UP) { // TODO: === ?
$fig = pow(10, $decimals);
$rounded_total = (ceil($fig * $amount) + ceil($fig * $amount - ceil($fig * $amount))) / $fig;
@@ -356,7 +354,7 @@ class Migration_TaxAmount extends Migration
$decimals = totals_decimals();
foreach ($sales_taxes as $row_number => $sales_tax) {
$sale_tax_amount = (float)$sales_tax['sale_tax_amount'];
$sale_tax_amount = $sales_tax['sale_tax_amount'];
$rounding_code = $sales_tax['rounding_code'];
$rounded_sale_tax_amount = $sale_tax_amount;

View File

@@ -1,65 +0,0 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
/**
* Migration to sanitize existing image filenames by replacing spaces with underscores
* This fixes issue #4372 where thumbnails failed to load for images with spaces in filenames
*/
class FixImageFilenameSpaces extends Migration
{
/**
* Perform a migration.
*/
public function up(): void
{
$db = \Config\Database::connect();
$builder = $db->table('ospos_items');
// Get all items with pic_filename containing spaces
$query = $builder->like('pic_filename', ' ', 'both')->get();
$items = $query->getResult();
foreach ($items as $item) {
$old_filename = $item->pic_filename;
$ext = pathinfo($old_filename, PATHINFO_EXTENSION);
$base_name = pathinfo($old_filename, PATHINFO_FILENAME);
// Sanitize the filename by replacing spaces and special characters
$sanitized_name = preg_replace('/[^a-zA-Z0-9_\-\.]/', '_', $base_name);
$new_filename = $sanitized_name . '.' . $ext;
// Rename the file on the filesystem
$old_path = FCPATH . 'uploads/item_pics/' . $old_filename;
$new_path = FCPATH . 'uploads/item_pics/' . $new_filename;
if (file_exists($old_path)) {
// Rename the original file
if (rename($old_path, $new_path)) {
// Check if thumbnail exists and rename it too
$old_thumb = FCPATH . 'uploads/item_pics/' . $base_name . '_thumb.' . $ext;
$new_thumb = FCPATH . 'uploads/item_pics/' . $sanitized_name . '_thumb.' . $ext;
if (file_exists($old_thumb)) {
rename($old_thumb, $new_thumb);
}
// Update database record
$builder->where('item_id', $item->item_id)
->update(['pic_filename' => $new_filename]);
}
}
}
}
/**
* Revert a migration.
* Note: This migration does not support rollback as the original filenames are lost
*/
public function down(): void
{
// This migration cannot be safely reversed as the original filenames are lost
// after sanitization.
}
}

View File

@@ -1,20 +0,0 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class PluginConfigTableCreate extends Migration
{
public function up(): void
{
log_message('info', 'Migrating plugin_config table started');
execute_script(APPPATH . 'Database/Migrations/sqlscripts/3.4.1_PluginConfigTableCreate.sql');
}
public function down(): void
{
$this->forge->dropTable('plugin_config', true);
}
}

View File

@@ -1,7 +0,0 @@
CREATE TABLE IF NOT EXISTS `ospos_plugin_config` (
`key` varchar(100) NOT NULL,
`value` text NOT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
PRIMARY KEY (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@@ -1,24 +0,0 @@
<?php
use CodeIgniter\Events\Events;
if (!function_exists('plugin_content')) {
function plugin_content(string $section, array $data = []): string
{
$results = Events::trigger("view:{$section}", $data);
if (is_array($results)) {
return implode('', array_filter($results, fn($r) => is_string($r)));
}
return is_string($results) ? $results : '';
}
}
if (!function_exists('plugin_content_exists')) {
function plugin_content_exists(string $section): bool
{
$observers = Events::listRegistered("view:{$section}");
return !empty($observers);
}
}

View File

@@ -48,7 +48,7 @@ function transform_headers(array $headers, bool $readonly = false, bool $editabl
'field' => key($element),
'title' => current($element),
'switchable' => $element['switchable'] ?? !preg_match('(^$|&nbsp)', current($element)),
'escape' => !preg_match("/(edit|email|messages|item_pic)/", key($element)) && !(isset($element['escape']) && !$element['escape']),
'escape' => !preg_match("/(edit|email|messages|item_pic|customer_name|note)/", key($element)) && !(isset($element['escape']) && !$element['escape']),
'sortable' => $element['sortable'] ?? current($element) != '',
'checkbox' => $element['checkbox'] ?? false,
'class' => isset($element['checkbox']) || preg_match('(^$|&nbsp)', current($element)) ? 'print_hide' : '',
@@ -470,8 +470,7 @@ function get_item_data_row(object $item): array
: glob("./uploads/item_pics/$item->pic_filename");
if (sizeof($images) > 0) {
$image_path = ltrim($images[0], './');
$image .= '<a class="rollover" href="' . base_url(implode('/', array_map('rawurlencode', explode('/', $image_path)))) . '"><img alt="Image thumbnail" src="' . site_url('items/PicThumb/' . rawurlencode(pathinfo($images[0], PATHINFO_BASENAME))) . '"></a>';
$image .= '<a class="rollover" href="' . base_url($images[0]) . '"><img alt="Image thumbnail" src="' . site_url('items/PicThumb/' . pathinfo($images[0], PATHINFO_BASENAME)) . '"></a>';
}
}

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "كلمة المرور الحالية غير صحيحة.",
"employee" => "موظف",
"error_adding_updating" => "خطاء فى إضافة/تعديل موظف.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "لايمكن حذف المستخدم admin الخاص بنسخة العرض.",
"error_updating_demo_admin" => "لايمكن تغيير بيانات المستخدم admin الخاص بنسخة العرض.",
"language" => "اللغة",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "سعر التكلفة مطلوب.",
"count" => "تحديث المخزون",
"csv_import_failed" => "فشل الإستيراد من اكسل",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "الملف الذى رفعته إما فارغ أو أنه مختلف البنية.",
"csv_import_partially_failed" => "يوجد خطأ بنسبة {0} في استيراد الاصناف في السطر: {1}. لم يتم استيرادهم.",
"csv_import_success" => "تم استيراد الأصناف بنجاح.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "كلمة المرور الحالية غير صحيحة.",
"employee" => "موظف",
"error_adding_updating" => "خطاء فى إضافة/تعديل موظف.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "لايمكن حذف المستخدم admin الخاص بنسخة العرض.",
"error_updating_demo_admin" => "لايمكن تغيير بيانات المستخدم admin الخاص بنسخة العرض.",
"language" => "اللغة",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "سعر التكلفة مطلوب.",
"count" => "تحديث المخزون",
"csv_import_failed" => "فشل الإستيراد من اكسل",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "الملف الذى رفعته إما فارغ أو أنه مختلف البنية.",
"csv_import_partially_failed" => "يوجد خطأ بنسبة {0} في استيراد الاصناف في السطر: {1}. لم يتم استيرادهم.",
"csv_import_success" => "تم استيراد الأصناف بنجاح.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Hazirki Şifrə düzgün deyil.",
"employee" => "Əməkdaş",
"error_adding_updating" => "Əməkdaş əlavə etməsk və ya yeniləməsi baş vermədi.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Demo administrator istifadəçisini silə bilməzsiniz.",
"error_updating_demo_admin" => "Demo administrator istifadəçisini dəyişə bilməzsiniz.",
"language" => "Dil",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Topdan satiış - doldurulması vacib sahə.",
"count" => "inventorun yenilənməsi",
"csv_import_failed" => "səhv csv import",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Yüklənmiş faylda məlumat yoxdur və ya düzgün formatlanmır.",
"csv_import_partially_failed" => "Xətlərdə {0} element idxalı uğursuzluq (lar) var: {1}. Heç bir sıra idxal edilmədi.",
"csv_import_success" => "Malların İdxalı Uğurla Həyata Keçdi.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Текущата парола е невалидна.",
"employee" => "Служител",
"error_adding_updating" => "Добавянето или актуализирането на служителите е неуспешно.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Не може да изтриете Пробният Администратор.",
"error_updating_demo_admin" => "Не може да промените Пробният Администратор.",
"language" => "Език",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Wholesale Price is a required field.",
"count" => "Update Inventory",
"csv_import_failed" => "CSV import failed",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "The uploaded file has no data or is formatted incorrectly.",
"csv_import_partially_failed" => "Item import successful with some failures:",
"csv_import_success" => "Item import successful.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Trenutna lozinka je nevažeća.",
"employee" => "Zaposlenik",
"error_adding_updating" => "Dodavanje ili ažuriranje zaposlenika nije uspjelo.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Ne možete izbrisati demo korisnika administratora.",
"error_updating_demo_admin" => "Ne možete promijeniti korisnika demo administratora.",
"language" => "Jezik",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Fakturna cijena je obavezno polje.",
"count" => "Ažuriraj zalihu",
"csv_import_failed" => "Uvoz CSV-a nije uspio",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Učitana CSV datoteka nema podatke ili je pogrešno formatirana.",
"csv_import_partially_failed" => "Bilo je {0} grešaka pri uvozu stavke na liniji: {1}. Nijedan red nije uvezen.",
"csv_import_success" => "Uvoz CSV stavke je uspješan.",

View File

@@ -14,8 +14,6 @@ return [
'current_password_invalid' => "وشەی نهێنی ئێستا نادروستە.",
'employee' => "فەرمانبەر",
'error_adding_updating' => "زیادکردن یان نوێکردنەوەی کارمەند سەرکەوتوو نەبوو.",
'error_deleting_admin' => "",
'error_updating_admin' => "",
'error_deleting_demo_admin' => "ناتوانیت بەکارهێنەری ئەدمینی تاقیکردنەوەیی بسڕیتەوە.",
'error_updating_demo_admin' => "ناتوانیت بەکارهێنەری ئەدمین تاقیکردنەوەیی بگۆڕیت.",
'language' => "زمان",

View File

@@ -26,7 +26,6 @@ return [
'cost_price_required' => "نرخی جوملە خانەیەکی پێویستە.",
'count' => "جەرد نوێ بکەوە",
'csv_import_failed' => "هاوردەکردنی CSV سەرکەوتوو نەبوو",
'csv_import_invalid_location' => "",
'csv_import_nodata_wrongformat' => "پەڕگەی CSV بارکراو هیچ داتایەکی نییە یان بە هەڵە فۆرمات کراوە.",
'csv_import_partially_failed' => "{0} شکستی هاوردەکردنی بابەتی لەسەر هێڵەکان هەبوو: {1}. هیچ ڕیزێک هاوردە نەکرا.",
'csv_import_success' => "بابەتی هاوردەکردنی CSV سەرکەوتوو بوو.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "",
"employee" => "",
"error_adding_updating" => "",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "",
"error_updating_demo_admin" => "",
"language" => "",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Musíte zadat nákupní cenu.",
"count" => "Upravit množství",
"csv_import_failed" => "Import z CSVu se nepovedl",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Nahraný soubor neobsahuje žádná data nebo má špatný formát.",
"csv_import_partially_failed" => "Při importu položek došlo k několika chybám:",
"csv_import_success" => "Import položek proběhl bez chyby.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Current Password is invalid.",
"employee" => "Employee",
"error_adding_updating" => "Employee add or update failed.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "You can not delete the demo admin user.",
"error_updating_demo_admin" => "You can not change the demo admin user.",
"language" => "Language",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "",
"count" => "",
"csv_import_failed" => "",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "",
"csv_import_partially_failed" => "",
"csv_import_success" => "",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "",
"employee" => "Mitarbeiter",
"error_adding_updating" => "Fehler beim Hinzufügen/Ändern",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Sie können den Admin nicht löschen",
"error_updating_demo_admin" => "Sie können den Admin nicht ändern",
"language" => "",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Einstandspreis ist erforderlich",
"count" => "Ändere Bestand",
"csv_import_failed" => "CSV Import fehlerhaft",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Your uploaded file has no data or wrong format",
"csv_import_partially_failed" => "Most Items imported. But some were not, here is the list",
"csv_import_success" => "Import of Items successful",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Aktuelles Passwort ist ungültig.",
"employee" => "Mitarbeiter",
"error_adding_updating" => "Fehler beim Hinzufügen/Ändern.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Sie können den Demo-Administrator nicht löschen.",
"error_updating_demo_admin" => "Sie können den Demo-Administrator nicht verändern.",
"language" => "Sprache",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Der Großhandelspreis ist ein Pflichtfeld.",
"count" => "Ändere Bestand",
"csv_import_failed" => "CSV Import fehlgeschlagen",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Die hochgeladene Datei enthält keine Daten oder ist falsch formatiert.",
"csv_import_partially_failed" => "{0} Artikel-Import Fehler in Zeile: {1}. Keine Reihen wurden importiert.",
"csv_import_success" => "Artikelimport erfolgreich.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "",
"employee" => "",
"error_adding_updating" => "",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "",
"error_updating_demo_admin" => "",
"language" => "",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "",
"count" => "",
"csv_import_failed" => "",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "",
"csv_import_partially_failed" => "",
"csv_import_success" => "",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Wholesale Price is a required field.",
"count" => "Update Inventory",
"csv_import_failed" => "CSV import failed",
"csv_import_invalid_location" => "Invalid stock location(s) found: {0}. Only valid stock locations are allowed.",
"csv_import_nodata_wrongformat" => "The uploaded CSV file has no data or is formatted incorrectly.",
"csv_import_partially_failed" => "There were {0} item import failure(s) on line(s): {1}. No rows were imported.",
"csv_import_success" => "Item CSV import successful.",

View File

@@ -1,27 +0,0 @@
<?php
return [
// Plugin Management
"plugins" => "Plugins",
"plugin_management" => "Plugin Management",
"plugin_name" => "Plugin Name",
"plugin_description" => "Description",
"plugin_version" => "Version",
"plugin_status" => "Status",
"plugin_enabled" => "Plugin enabled successfully",
"plugin_enable_failed" => "Failed to enable plugin",
"plugin_disabled" => "Plugin disabled successfully",
"plugin_disable_failed" => "Failed to disable plugin",
"plugin_uninstalled" => "Plugin uninstalled successfully",
"plugin_uninstall_failed" => "Failed to uninstall plugin",
"plugin_not_found" => "Plugin not found",
"plugin_no_config" => "This plugin has no configuration options",
"settings_saved" => "Plugin settings saved successfully",
"settings_save_failed" => "Failed to save plugin settings",
"enable" => "Enable",
"disable" => "Disable",
"configure" => "Configure",
"uninstall" => "Uninstall",
"no_plugins_found" => "No plugins found",
"active" => "Active",
"inactive" => "Inactive",
];

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Contraseña Actual Inválida.",
"employee" => "Empleado",
"error_adding_updating" => "Error al agregar/actualizar empleado.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "No puedes borrar el usuario admin del demo.",
"error_updating_demo_admin" => "No puedes cambiar el usuario admin del demo.",
"language" => "Idioma",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Precio al Por Mayor es un campo requerido.",
"count" => "Actualizar Inventario",
"csv_import_failed" => "Falló la importación de Hoja de Cálculo",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "El archivo subido no tiene datos o el formato es incorrecto.",
"csv_import_partially_failed" => "Hubo {0} falla(s) en la importación de producto(s) en la(s) línea(s): {1}. Ninguna fila ha sido importada.",
"csv_import_success" => "Se importaron los articulos exitosamente.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "La contraseña actual es inválida.",
"employee" => "Empleado",
"error_adding_updating" => "Agregar ó Actualizar empleado ha fallado.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "No puede borrar el usuario demo de administrador.",
"error_updating_demo_admin" => "No puede cambiar el usuario demo de administrador.",
"language" => "Idioma",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "El precio de mayoreo es requerido.",
"count" => "Actualizar inventario",
"csv_import_failed" => "",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "",
"csv_import_partially_failed" => "",
"csv_import_success" => "",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "گذرواژه فعلی نامعتبر است.",
"employee" => "کارمند",
"error_adding_updating" => "افزودن یا به روزرسانی کارکنان انجام نشد.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "شما نمی توانید کاربر مدیر نسخه ی نمایشی را حذف کنید.",
"error_updating_demo_admin" => "شما نمی توانید کاربر مدیر نسخه ی نمایشی را تغییر دهید.",
"language" => "زبان",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "قیمت عمده فروشی یک زمینه ضروری است.",
"count" => "به روزرسانی موجودی",
"csv_import_failed" => "واردات سی‌اس‌وی انجام نشد",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "پرونده سی‌اس‌وی آپلود شده داده ای ندارد یا به طور نادرست قالب بندی شده است.",
"csv_import_partially_failed" => "در خط (ها){0} شکست واردات کالا وجود دارد:{1}. هیچ سطر وارد نشده است.",
"csv_import_success" => "وارد کردن سی‌اس‌وی مورد موفقیت آمیز است.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Le mot de passe actuel est invalide.",
"employee" => "Employé",
"error_adding_updating" => "Erreur d'ajout/édition d'employé.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Vous ne pouvez pas supprimer l'utilisateur de démonstration admin.",
"error_updating_demo_admin" => "Vous ne pouvez pas modifier l'utilisateur de démonstration admin.",
"language" => "Langue",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Le prix de gros est requis.",
"count" => "Mise à jour de l'inventaire",
"csv_import_failed" => "Échec d'import CSV",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Le CSV envoyé ne contient aucune donnée, ou elles sont dans un format erroné.",
"csv_import_partially_failed" => "Il y a eu {0} importation(s) d'articles échoué(s) au(x) ligne(s) : {1}. Aucune ligne n'a été importée.",
"csv_import_success" => "Importation des articles réussie.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "הסיסמה הנוכחית אינה חוקית.",
"employee" => "עובד",
"error_adding_updating" => "הוספה או עדכון של עובד נכשלה.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "לא ניתן למחוק את משתמש המנהל ההדגמה.",
"error_updating_demo_admin" => "לא ניתן לשנות את משתמש המנהל ההדגמה.",
"language" => "שפה",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "מחיר סיטונאי הינו שדה חובה.",
"count" => "עדכן מלאי",
"csv_import_failed" => "ייבוא אקסל נכשל",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "בקובץ שהועלה אין נתונים או פורמט שגוי.",
"csv_import_partially_failed" => "ייבוא פריט הצליח עם מספר שגיאות:",
"csv_import_success" => "ייבוא הפריט הצליח.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "",
"employee" => "Radnik",
"error_adding_updating" => "Greška kod dodavanja/ažuriranja radnika",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Ne možete obrisati demo admin korisnika",
"error_updating_demo_admin" => "Ne možete promijeniti demo admin korisnika",
"language" => "",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Nabavna cijena je potrebna",
"count" => "Ažuriraj inveturu",
"csv_import_failed" => "Greška kod uvoza iz CSV-a",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Your uploaded file has no data or wrong format",
"csv_import_partially_failed" => "Most Items imported. But some were not, here is the list",
"csv_import_success" => "Import of Items successful",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "",
"employee" => "Munkavállaló",
"error_adding_updating" => "Hiba a munkavállaló módosításánál/hozzáadásánál",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Nem tudja törölni a demo admin felhasználót",
"error_updating_demo_admin" => "Nem tudja módosítani a demo admin felhasználót",
"language" => "",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Bekerülési ár kötelező mező",
"count" => "Raktárkészlet módosítása",
"csv_import_failed" => "CSV import sikertelen",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "A feltöltött fájlban nincs adat, vagy rossz formátum.",
"csv_import_partially_failed" => "Most Items imported. But some were not, here is the list",
"csv_import_success" => "Import of Items successful",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "",
"employee" => "",
"error_adding_updating" => "",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "",
"error_updating_demo_admin" => "",
"language" => "",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "",
"count" => "",
"csv_import_failed" => "",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "",
"csv_import_partially_failed" => "",
"csv_import_success" => "",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Kata kunci sekarang salah.",
"employee" => "Karyawan",
"error_adding_updating" => "Kesalahan menambah / memperbarui karyawan.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Anda tidak dapat menghapus Demo admin user.",
"error_updating_demo_admin" => "Anda tidak dapat mengubah Demo admin user.",
"language" => "Bahasa",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Harga beli harus diisi.",
"count" => "Mutasi Inventori",
"csv_import_failed" => "Gagal impor CSV",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Berkas CSV terunggah tidak berisi data atau formatnya salah.",
"csv_import_partially_failed" => "Terdapat {0} item gagal impor pada baris: {1}. Tidak ada baris yang diimpor.",
"csv_import_success" => "Impor item CSV berhasil.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Password corrente non valida.",
"employee" => "Impiegato",
"error_adding_updating" => "Aggiunta o aggiornamento di impiegati fallito.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Non puoi eliminare l'utente admin demo.",
"error_updating_demo_admin" => "Non puoi cambiare l'utente admin demo.",
"language" => "Lingua",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Prezzo all'ingrosso è un campo obbligatorio.",
"count" => "Aggiorna Inventario",
"csv_import_failed" => "Importazione CSV fallita",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "L'upload del file non ha dati o non è formattato correttamente.",
"csv_import_partially_failed" => "Si sono verificati {0} errori di importazione degli elementi nelle righe: {1}. Nessuna riga è stata importata.",
"csv_import_success" => "Importazione CSV dell'articolo riuscita.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "ពាក្យសម្ងាត់បច្ចុប្បន្ន មិនត្រឹមត្រូវ។",
"employee" => "បុគ្គលិក",
"error_adding_updating" => "បន្ថែម ឬកែប្រែបុគ្គលិកមិនបានសំរេច។",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "អ្នកមិនអាចលុប គណនីសាកល្បង បានទេ។",
"error_updating_demo_admin" => "អ្នកមិនអាចកែប្រែ គណនីសាកល្បងបានទេ។",
"language" => "ភាសា",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "ត្រូវការតម្លៃលក់ដុំជាចាំបាច់។",
"count" => "កែប្រែ ទំនិញក្នុងស្តុក",
"csv_import_failed" => "CSV បញ្ចូលមិនបានសំរេច",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "ដាក់បញ្ជុល CSV មិនមានទិន្នន័យ ឬទំរង់មិនត្រឹមត្រូវ។",
"csv_import_partially_failed" => "មានទំននិញ {0} បញ្ជូលមិនបានសំរេច នៅជួរ: {1} ។ គ្មានជួរណាមួយត្រូវបានបញ្ជូលនោះទេ។",
"csv_import_success" => "ទំនិញក្នុង CSV បញ្ចូលបានសំរេច។",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Password ປັດຈຸບັນບໍ່ຖືກຕ້ອງ.",
"employee" => "ພະນັກງານ",
"error_adding_updating" => "ເພີ່ມ ຫຼື ແກ້ໄຂ ພະນັກງານ ບໍ່ສຳເລັດ.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "ທ່ານບໍ່ສາມາດລຶບບັນຊີທົດລອງຜູ້ດູແລລະບົບໄດ້.",
"error_updating_demo_admin" => "ທ່ານບໍ່ສາມາດປ່ຽນແປງບັນຊີທົດລອງຜູ້ດູແລລະບົບໄດ້.",
"language" => "ພາສາ",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "ກະລຸນາກຳນົດລາຄາຕົ້ນທຶນ.",
"count" => "ອັບເດດປະລິມານສິນຄ້າໃນສາງ",
"csv_import_failed" => "CSV import failed",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "The uploaded file has no data or is formatted incorrectly.",
"csv_import_partially_failed" => "Item import successful with some failures:",
"csv_import_success" => "Item import successful.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "",
"employee" => "",
"error_adding_updating" => "",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "",
"error_updating_demo_admin" => "",
"language" => "",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "",
"count" => "",
"csv_import_failed" => "",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "",
"csv_import_partially_failed" => "",
"csv_import_success" => "",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "",
"employee" => "",
"error_adding_updating" => "",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "",
"error_updating_demo_admin" => "",
"language" => "",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "",
"count" => "",
"csv_import_failed" => "",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "",
"csv_import_partially_failed" => "",
"csv_import_success" => "",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Huidig paswoord is ongeldig.",
"employee" => "Werknemer",
"error_adding_updating" => "Fout bij het toevoegen/aanpassen medewerker.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Je kan de demo gebruilker niet verwijderen.",
"error_updating_demo_admin" => "Jij kan de demo gebruiker niet veranderen.",
"language" => "Taal",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Groothandelsprijs is een verplicht veld.",
"count" => "Update Stock",
"csv_import_failed" => "CSV import mislukt",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Het geüploade CSV-bestand bevat geen gegevens of is onjuist geformatteerd.",
"csv_import_partially_failed" => "Er waren {0} artikel import fout(en) op regel(s): {1}. Er werden geen rijen geïmporteerd.",
"csv_import_success" => "Artikel CSV import geslaagd.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Huidige wachtwoord is ongeldig.",
"employee" => "Werknemer",
"error_adding_updating" => "Werknemer toevoegen of bijwerken mislukt.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Kan de demo admin gebruiker niet verwijderen.",
"error_updating_demo_admin" => "Kan de demo admin gebruiker niet wijzigen.",
"language" => "Taal",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Inkoopprijs is een vereist veld.",
"count" => "Voorraad bijwerken",
"csv_import_failed" => "CSV importeren mislukt",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Het geüploade CSV-bestand bevat geen gegevens or heeft de verkeerde indeling.",
"csv_import_partially_failed" => "Er zijn {0} artikel import fout(en) in lijn(en): {1}. Geen rijen geïmporteerd.",
"csv_import_success" => "Artikel CSV geïmporteerd.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "",
"employee" => "",
"error_adding_updating" => "",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "",
"error_updating_demo_admin" => "",
"language" => "",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "",
"count" => "",
"csv_import_failed" => "",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "",
"csv_import_partially_failed" => "",
"csv_import_success" => "",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Senha atual inválida.",
"employee" => "Funcionário",
"error_adding_updating" => "Erro ao adicionar/atualizar funcionário.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Você não pode excluir o usuário administrador de demonstração.",
"error_updating_demo_admin" => "Você não pode alterar o usuário de demonstração de administração.",
"language" => "Linguagem",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Preço de custo é um campo obrigatório.",
"count" => "Acrescentar ao Inventário",
"csv_import_failed" => "Importação do CSV falhou",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Seu arquivo enviado não contém dados ou formato errado.",
"csv_import_partially_failed" => "Houve {0} falha na importação de itens na(s) linha(s): {1}. Nenhuma linha foi importada.",
"csv_import_success" => "Importação de Itens com sucesso.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "",
"employee" => "",
"error_adding_updating" => "",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "",
"error_updating_demo_admin" => "",
"language" => "",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "",
"count" => "",
"csv_import_failed" => "",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "",
"csv_import_partially_failed" => "",
"csv_import_success" => "",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Текущий пароль введен неверно.",
"employee" => "Сотрудник",
"error_adding_updating" => "Ошибка при добавлении/обновлении сотрудника.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Вы не можете удалить демо-администратора.",
"error_updating_demo_admin" => "Вы не можете изменить демо-администратора.",
"language" => "Язык",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Оптовая цена - обязательное поле.",
"count" => "Обновление запасов",
"csv_import_failed" => "Ошибка импорта CSV",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Загруженный файл CSV не содержит данных или имеет неправильный формат.",
"csv_import_partially_failed" => "В строке (строках) произошло {0} ошибок импорта: {1}. Ничего не было импортировано.",
"csv_import_success" => "Товар успешно импортирован из CSV.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Nuvarande lösenord är fel.",
"employee" => "Anställd",
"error_adding_updating" => "Anställd lägg till eller uppdatering misslyckades.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Du kan inte radera demo admin-användaren.",
"error_updating_demo_admin" => "Du kan inte ändra demo admin-användaren.",
"language" => "Språk",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Grossistpris är ett obligatoriskt fält.",
"count" => "Uppdatera Inventory",
"csv_import_failed" => "CSV-import misslyckades",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Den uppladdade filen har ingen data eller är formaterad felaktigt.",
"csv_import_partially_failed" => "Det fanns{0} importfel (er) på rad (er):{1}. Inga rader importerades.",
"csv_import_success" => "Artikelimporten lyckades.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Nenosiri la sasa si sahihi.",
"employee" => "Mfanyakazi",
"error_adding_updating" => "Kuongeza au kusasisha mfanyakazi kumeshindikana.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Huwezi kufuta mtumiaji wa admin wa majaribio.",
"error_updating_demo_admin" => "Huwezi kubadilisha mtumiaji wa admin wa majaribio.",
"language" => "Lugha",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Bei ya Jumla ni kiashiria kinachohitajika.",
"count" => "Sasisha Hisa",
"csv_import_failed" => "Uingizaji wa CSV umeshindikana",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Faili ya CSV iliyopakiwa haina data au imepangwa vibaya.",
"csv_import_partially_failed" => "Kumekuwa na makosa {0} ya uingizaji wa bidhaa kwenye mstari: {1}. Hakuna safu zilizoingizwa.",
"csv_import_success" => "Uingizaji wa Bidhaa kutoka CSV umefanikiwa.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Nenosiri la sasa si sahihi.",
"employee" => "Mfanyakazi",
"error_adding_updating" => "Kuongeza au kusasisha mfanyakazi kumeshindikana.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Huwezi kufuta mtumiaji wa admin wa majaribio.",
"error_updating_demo_admin" => "Huwezi kubadilisha mtumiaji wa admin wa majaribio.",
"language" => "Lugha",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Bei ya Jumla ni kiashiria kinachohitajika.",
"count" => "Sasisha Hisa",
"csv_import_failed" => "Uingizaji wa CSV umeshindikana",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Faili ya CSV iliyopakiwa haina data au imepangwa vibaya.",
"csv_import_partially_failed" => "Kumekuwa na makosa {0} ya uingizaji wa bidhaa kwenye mstari: {1}. Hakuna safu zilizoingizwa.",
"csv_import_success" => "Uingizaji wa Bidhaa kutoka CSV umefanikiwa.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Current Password is invalid.",
"employee" => "Employee",
"error_adding_updating" => "Employee add or update failed.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "You can not delete the demo admin user.",
"error_updating_demo_admin" => "You can not change the demo admin user.",
"language" => "Language",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Wholesale Price is a required field.",
"count" => "Update Inventory",
"csv_import_failed" => "CSV import failed",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "The uploaded CSV file has no data or is formatted incorrectly.",
"csv_import_partially_failed" => "There were {0} item import failure(s) on line(s): {1}. No rows were imported.",
"csv_import_success" => "Item CSV import successful.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "รหัสผ่านปัจจุบันไม่ถูกต้อง",
"employee" => "พนักงาน",
"error_adding_updating" => "การเพิ่มหรือปรับปรุงข้อมูลพนักงานผิดพลาด",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "คุณไม่สามารถลบผู้ใช้งานสำหรับการเดโม้ได้",
"error_updating_demo_admin" => "คุณไม่สามารถทำการเปลี่ยนข้อมูลผู้ใช้งานเดโม้ได้",
"language" => "ภาษา",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "ต้องกรอกราคาขายส่ง",
"count" => "แก้ไขจำนวนสินค้าคงคลัง",
"csv_import_failed" => "นำเข้าข้อมูล CSV ล้มเหลว",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Your uploaded file has no data or wrong format",
"csv_import_partially_failed" => "มีรายการ {0} รายการที่นำเข้าล้มเหลว : {1} รายการที่ยังไม่ได้นำเข้า",
"csv_import_success" => "Import of Items successful",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Current Password is invalid.",
"employee" => "Employee",
"error_adding_updating" => "Employee add or update failed.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "You can not change the demo admin user.",
"error_updating_demo_admin" => "You can not delete the demo admin user.",
"language" => "Language",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Purchase Price is a required field.",
"count" => "Update Inventory",
"csv_import_failed" => "CSV import failed",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "The uploaded file has no data or is formatted incorrectly.",
"csv_import_partially_failed" => "Customer import successful with some failures:",
"csv_import_success" => "Item import successful.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Var Olan Parola geçersiz.",
"employee" => "Personel",
"error_adding_updating" => "Personel ekleme/güncelleme hatası.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Admin güncellenemez.",
"error_updating_demo_admin" => "Admin silinemez.",
"language" => "Dil",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Toptan Fiyatı zorunlu alandır.",
"count" => "Stoğu Güncelle",
"csv_import_failed" => "CSV aktarım hatası",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Yüklenen dosya herhangi bir veri içermiyor veya hatalı formatta.",
"csv_import_partially_failed" => "Bazı ürünler aktarılamadı. Aktarılamayanlar listesi.",
"csv_import_success" => "Ürün aktarımı başarılı.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "Поточний пароль невірний.",
"employee" => "Працівник",
"error_adding_updating" => "Помилка при додаванні/оновлені працівника.",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "Ви не можете видалити аккаунт користувача.",
"error_updating_demo_admin" => "Ви не можете змінити аккаунт користувача.",
"language" => "Мова",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "Оптова ціна - обов'язкове поле.",
"count" => "Оновити інвентар",
"csv_import_failed" => "Помилка імпорту CSV",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "Завандажений файл порожній або відформатований неправильно.",
"csv_import_partially_failed" => "У рядках виявлено {0} помилки імпортування елементів: {1}. Не було імпортовано жодних рядків.",
"csv_import_success" => "Імпорт товару CSV успішний.",

View File

@@ -14,8 +14,6 @@ return [
"current_password_invalid" => "",
"employee" => "",
"error_adding_updating" => "",
"error_deleting_admin" => "",
"error_updating_admin" => "",
"error_deleting_demo_admin" => "",
"error_updating_demo_admin" => "",
"language" => "",

View File

@@ -26,7 +26,6 @@ return [
"cost_price_required" => "",
"count" => "",
"csv_import_failed" => "",
"csv_import_invalid_location" => "",
"csv_import_nodata_wrongformat" => "",
"csv_import_partially_failed" => "",
"csv_import_success" => "",

Some files were not shown because too many files have changed in this diff Show More