mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-05-26 01:05:07 -04:00
Compare commits
30 Commits
feature/ap
...
fix/pr-436
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39864c4e86 | ||
|
|
423c06142c | ||
|
|
a240c933fd | ||
|
|
66b6c99384 | ||
|
|
a1c062ab13 | ||
|
|
003df2bd7c | ||
|
|
eec567ee15 | ||
|
|
e7c610acd0 | ||
|
|
cff8762d07 | ||
|
|
85889b6e65 | ||
|
|
6818f02ef9 | ||
|
|
436696b11b | ||
|
|
9a2b308647 | ||
|
|
1f55d96580 | ||
|
|
b2fadea44a | ||
|
|
0fdb3ba37b | ||
|
|
d7b2264ac1 | ||
|
|
a229bf6031 | ||
|
|
977fa5647b | ||
|
|
52b0a83190 | ||
|
|
f25a0f5b09 | ||
|
|
f0f288797a | ||
|
|
63083a0946 | ||
|
|
3a33098776 | ||
|
|
ca6a1b35af | ||
|
|
418580a52d | ||
|
|
31d25e06dc | ||
|
|
b1819b3b36 | ||
|
|
6705420373 | ||
|
|
d6b767c80a |
10
.github/workflows/phpunit.yml
vendored
10
.github/workflows/phpunit.yml
vendored
@@ -111,7 +111,15 @@ jobs:
|
||||
env:
|
||||
CI_ENVIRONMENT: testing
|
||||
MYSQL_HOST_NAME: 127.0.0.1
|
||||
run: composer test
|
||||
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
|
||||
|
||||
- name: Stop MariaDB
|
||||
if: always()
|
||||
|
||||
72
.github/workflows/update-issue-templates.yml
vendored
Normal file
72
.github/workflows/update-issue-templates.yml
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
name: Update Issue Templates
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
|
||||
jobs:
|
||||
update-templates:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Fetch releases and update templates
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
# Fetch releases from GitHub API
|
||||
RELEASES=$(gh api repos/${{ github.repository }}/releases --jq '.[].tag_name' | head -n 10)
|
||||
|
||||
# Create temporary file with options
|
||||
OPTIONS_FILE=$(mktemp)
|
||||
echo " - development (unreleased)" >> "$OPTIONS_FILE"
|
||||
while IFS= read -r release; do
|
||||
echo " - opensourcepos $release" >> "$OPTIONS_FILE"
|
||||
done <<< "$RELEASES"
|
||||
|
||||
update_template() {
|
||||
local template="$1"
|
||||
local template_path=".github/ISSUE_TEMPLATE/$template"
|
||||
|
||||
# Find the line numbers for the OpensourcePOS Version dropdown
|
||||
start_line=$(grep -n "label: OpensourcePOS Version" "$template_path" | cut -d: -f1)
|
||||
|
||||
if [ -z "$start_line" ]; then
|
||||
echo "Could not find OpensourcePOS Version in $template"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Find the options section and default line
|
||||
options_start=$((start_line + 3))
|
||||
default_line=$(grep -n "default:" "$template_path" | awk -F: -v opts="$options_start" '$1 > opts {print $1; exit}')
|
||||
|
||||
# Create new template file
|
||||
head -n $((options_start - 1)) "$template_path" > "${template_path}.new"
|
||||
cat "$OPTIONS_FILE" >> "${template_path}.new"
|
||||
tail -n +$default_line "$template_path" >> "${template_path}.new"
|
||||
mv "${template_path}.new" "$template_path"
|
||||
|
||||
echo "Updated $template"
|
||||
}
|
||||
|
||||
update_template "bug report.yml"
|
||||
update_template "feature_request.yml"
|
||||
|
||||
- name: Commit and push changes
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git add .github/ISSUE_TEMPLATE/*.yml
|
||||
if git diff --staged --quiet; then
|
||||
echo "No changes to commit"
|
||||
else
|
||||
git commit -m "Update issue templates with latest releases [skip ci]"
|
||||
git push
|
||||
fi
|
||||
295
API.md
295
API.md
@@ -1,295 +0,0 @@
|
||||
# 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?
|
||||
37
SECURITY.md
37
SECURITY.md
@@ -1,9 +1,9 @@
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
|
||||
- [Security Policy](#security-policy)
|
||||
- [Supported Versions](#supported-versions)
|
||||
- [Security Advisories](#security-advisories)
|
||||
- [Reporting a Vulnerability](#reporting-a-vulnerability)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
@@ -12,14 +12,35 @@
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We release patches for security vulnerabilities. Which versions are eligible to receive such patches depend on the CVSS v3.0 Rating:
|
||||
We release patches for security vulnerabilities.
|
||||
|
||||
| CVSS v3.0 | Supported Versions |
|
||||
| --------- | -------------------------------------------------- |
|
||||
| 7.3 | 3.3.5 |
|
||||
| 9.8 | 3.3.6 |
|
||||
| 6.8 | 3.4.2 |
|
||||
| Version | Supported |
|
||||
| --------- | ------------------ |
|
||||
| >= 3.4.2 | :white_check_mark: |
|
||||
| < 3.4.2 | :x: |
|
||||
|
||||
## Security Advisories
|
||||
|
||||
The following security vulnerabilities have been published:
|
||||
|
||||
### High Severity
|
||||
|
||||
| CVE | Vulnerability | CVSS | Published | Fixed In | Credit |
|
||||
|-----|--------------|------|-----------|----------|--------|
|
||||
| [CVE-2025-68434](https://github.com/opensourcepos/opensourcepos/security/advisories/GHSA-wjm4-hfwg-5w5r) | CSRF leading to Admin Creation | 8.8 | 2025-12-17 | 3.4.2 | @Nixon-H, @jekkos |
|
||||
| [CVE-2025-68147](https://github.com/opensourcepos/opensourcepos/security/advisories/GHSA-xgr7-7pvw-fpmh) | Stored XSS in Return Policy | 8.1 | 2025-12-17 | 3.4.2 | @Nixon-H, @jekkos |
|
||||
| [CVE-2025-66924](https://github.com/opensourcepos/opensourcepos/security/advisories/GHSA-gv8j-f6gq-g59m) | Stored XSS in Item Kits | 7.2 | 2026-03-04 | 3.4.2 | @hungnqdz, @omkaryepre |
|
||||
|
||||
### Medium Severity
|
||||
|
||||
| CVE | Vulnerability | CVSS | Published | Fixed In | Credit |
|
||||
|-----|--------------|------|-----------|----------|--------|
|
||||
| [CVE-2025-68658](https://github.com/opensourcepos/opensourcepos/security/advisories/GHSA-32r8-8r9r-9chw) | Stored XSS in Company Name | 4.3 | 2026-01-13 | 3.4.2 | @hungnqdz |
|
||||
|
||||
For a complete list including draft advisories, see our [GitHub Security Advisories page](https://github.com/opensourcepos/opensourcepos/security/advisories).
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report (suspected) security vulnerabilities to **[jeroen@steganos.dev](mailto:jeroen@steganos.dev)**. You will receive a response from us within 48 hours. If the issue is confirmed, we will release a patch as soon as possible depending on complexity but historically within a few days.
|
||||
Please report (suspected) security vulnerabilities to **[jeroen@steganos.dev](mailto:jeroen@steganos.dev)**.
|
||||
|
||||
You will receive a response from us within 48 hours. If the issue is confirmed, we will release a patch as soon as possible depending on complexity but historically within a few days.
|
||||
@@ -169,3 +169,8 @@ 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'];
|
||||
|
||||
@@ -461,8 +461,9 @@ 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' => $this->request->getPost('currency_symbol'),
|
||||
'currency_symbol' => htmlspecialchars($currency_symbol ?? ''),
|
||||
'currency_code' => $this->request->getPost('currency_code'),
|
||||
'language_code' => $exploded[0],
|
||||
'language' => $exploded[1],
|
||||
@@ -942,7 +943,9 @@ 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' => $this->request->getPost('invoice_type')
|
||||
'invoice_type' => Sale_lib::isValidInvoiceType($this->request->getPost('invoice_type'))
|
||||
? $this->request->getPost('invoice_type')
|
||||
: 'invoice'
|
||||
];
|
||||
|
||||
$success = $this->appconfig->batch_save($batch_save_data);
|
||||
|
||||
@@ -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->can_modify_employee($person_info->person_id, $current_user->person_id)) {
|
||||
if ($employee_id != NEW_ENTRY && !$this->employee->canModifyEmployee($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->can_modify_employee($target_employee->person_id, $current_user->person_id)) {
|
||||
if (!$this->employee->canModifyEmployee($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 = [];
|
||||
$is_admin = $this->employee->is_admin($current_user->person_id);
|
||||
$isAdmin = $this->employee->isAdmin($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 (!$is_admin && !$this->employee->has_grant($permission->permission_id, $current_user->person_id)) {
|
||||
if (!$isAdmin && !$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->is_admin($current_user->person_id)) {
|
||||
if (!$this->employee->isAdmin($current_user->person_id)) {
|
||||
foreach ($employees_to_delete as $emp_id) {
|
||||
if ($this->employee->is_admin((int)$emp_id)) {
|
||||
if ($this->employee->isAdmin((int)$emp_id)) {
|
||||
return $this->response->setJSON(['success' => false, 'message' => lang('Employees.error_deleting_admin')]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,19 @@ class Home extends Secure_Controller
|
||||
* @return string
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function getChangePassword(int $employee_id = -1): string // TODO: Replace -1 with a constant
|
||||
public function getChangePassword(int $employeeId = NEW_ENTRY): string
|
||||
{
|
||||
$person_info = $this->employee->get_info($employee_id);
|
||||
$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);
|
||||
foreach (get_object_vars($person_info) as $property => $value) {
|
||||
$person_info->$property = $value;
|
||||
}
|
||||
@@ -55,9 +65,20 @@ class Home extends Secure_Controller
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function postSave(int $employee_id = -1): ResponseInterface // TODO: Replace -1 with a constant
|
||||
public function postSave(int $employeeId = NEW_ENTRY): ResponseInterface
|
||||
{
|
||||
if (!empty($this->request->getPost('current_password')) && $employee_id != -1) {
|
||||
$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 ($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');
|
||||
@@ -66,7 +87,7 @@ class Home extends Secure_Controller
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => lang('Employees.password_minlength'),
|
||||
'id' => -1
|
||||
'id' => NEW_ENTRY
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -76,32 +97,32 @@ class Home extends Secure_Controller
|
||||
'hash_version' => 2
|
||||
];
|
||||
|
||||
if ($this->employee->change_password($employee_data, $employee_id)) {
|
||||
if ($this->employee->change_password($employee_data, $employeeId)) {
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'message' => lang('Employees.successful_change_password'),
|
||||
'id' => $employee_id
|
||||
'id' => $employeeId
|
||||
]);
|
||||
} else { // Failure // TODO: Replace -1 with constant
|
||||
} else {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => lang('Employees.unsuccessful_change_password'),
|
||||
'id' => -1
|
||||
'id' => NEW_ENTRY
|
||||
]);
|
||||
}
|
||||
} else { // TODO: Replace -1 with constant
|
||||
} else {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => lang('Employees.current_password_invalid'),
|
||||
'id' => -1
|
||||
'id' => NEW_ENTRY
|
||||
]);
|
||||
}
|
||||
} else { // TODO: Replace -1 with constant
|
||||
} else {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => lang('Employees.current_password_invalid'),
|
||||
'id' => -1
|
||||
'id' => NEW_ENTRY
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ class Items extends Secure_Controller
|
||||
**/
|
||||
public function getSearch(): ResponseInterface
|
||||
{
|
||||
$search = $this->request->getGet('search');
|
||||
$search = $this->request->getGet('search', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$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,6 +148,7 @@ 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);
|
||||
@@ -377,7 +378,7 @@ class Items extends Secure_Controller
|
||||
} else {
|
||||
$images = glob("./uploads/item_pics/$item_info->pic_filename");
|
||||
}
|
||||
$data['image_path'] = sizeof($images) > 0 ? base_url($images[0]) : '';
|
||||
$data['image_path'] = sizeof($images) > 0 ? base_url(implode('/', array_map('rawurlencode', explode('/', ltrim($images[0], './'))))) : '';
|
||||
} else {
|
||||
$data['image_path'] = '';
|
||||
}
|
||||
@@ -617,7 +618,7 @@ class Items extends Secure_Controller
|
||||
// Save item data
|
||||
$item_data = [
|
||||
'name' => $this->request->getPost('name'),
|
||||
'description' => $this->request->getPost('description'),
|
||||
'description' => $this->request->getPost('description', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
|
||||
'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')),
|
||||
@@ -768,10 +769,13 @@ 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' => $info['filename'],
|
||||
'raw_name' => $sanitized_name,
|
||||
'file_ext' => $file->guessExtension()
|
||||
];
|
||||
|
||||
@@ -872,12 +876,12 @@ class Items extends Secure_Controller
|
||||
$items_to_update = $this->request->getPost('item_ids');
|
||||
$item_data = [];
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1017,7 +1021,11 @@ class Items extends Secure_Controller
|
||||
}
|
||||
|
||||
if (!$is_failed_row) {
|
||||
$is_failed_row = $this->data_error_check($row, $item_data, $allowed_stock_locations, $attribute_definition_names, $attribute_data);
|
||||
$invalidLocations = $this->validateCSVStockLocations($row, $allowedStockLocations);
|
||||
if (!empty($invalidLocations)) {
|
||||
$isFailedRow = true;
|
||||
log_message('error', 'CSV import: Invalid stock location(s) found: ' . implode(', ', $invalidLocations));
|
||||
}
|
||||
}
|
||||
|
||||
// Remove false, null, '' and empty strings but keep 0
|
||||
@@ -1063,6 +1071,30 @@ 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
|
||||
*
|
||||
|
||||
@@ -755,8 +755,11 @@ class Sales extends Secure_Controller
|
||||
$data['sale_status'] = COMPLETED;
|
||||
$sale_type = SALE_TYPE_INVOICE;
|
||||
|
||||
// The PHP file name is the same as the invoice_type key
|
||||
$invoice_view = $this->config['invoice_type'];
|
||||
$invoice_type = $this->config['invoice_type'];
|
||||
if (!Sale_lib::isValidInvoiceType($invoice_type)) {
|
||||
$invoice_type = 'invoice';
|
||||
}
|
||||
$invoice_view = $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);
|
||||
@@ -1107,6 +1110,9 @@ 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;
|
||||
|
||||
@@ -267,6 +267,8 @@ 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;
|
||||
@@ -376,7 +378,7 @@ class Migration_Sales_Tax_Data extends Migration
|
||||
$decimals = totals_decimals();
|
||||
|
||||
foreach ($sales_taxes as $row_number => $sales_tax) {
|
||||
$sale_tax_amount = $sales_tax['sale_tax_amount'];
|
||||
$sale_tax_amount = (float)$sales_tax['sale_tax_amount'];
|
||||
$rounding_code = $sales_tax['rounding_code'];
|
||||
$rounded_sale_tax_amount = $sale_tax_amount;
|
||||
|
||||
|
||||
@@ -243,6 +243,8 @@ 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;
|
||||
@@ -354,7 +356,7 @@ class Migration_TaxAmount extends Migration
|
||||
$decimals = totals_decimals();
|
||||
|
||||
foreach ($sales_taxes as $row_number => $sales_tax) {
|
||||
$sale_tax_amount = $sales_tax['sale_tax_amount'];
|
||||
$sale_tax_amount = (float)$sales_tax['sale_tax_amount'];
|
||||
$rounding_code = $sales_tax['rounding_code'];
|
||||
$rounded_sale_tax_amount = $sale_tax_amount;
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<?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.
|
||||
}
|
||||
}
|
||||
15
app/Enums/RewardOperation.php
Normal file
15
app/Enums/RewardOperation.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
/**
|
||||
* Reward operation types for customer points adjustments.
|
||||
*
|
||||
* Used by Reward_lib to perform type-safe reward point operations.
|
||||
*/
|
||||
enum RewardOperation: string
|
||||
{
|
||||
case Deduct = 'deduct';
|
||||
case Restore = 'restore';
|
||||
case Adjust = 'adjust';
|
||||
}
|
||||
@@ -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('(^$| )', current($element)),
|
||||
'escape' => !preg_match("/(edit|email|messages|item_pic|customer_name|note)/", key($element)) && !(isset($element['escape']) && !$element['escape']),
|
||||
'escape' => !preg_match("/(edit|email|messages|item_pic)/", key($element)) && !(isset($element['escape']) && !$element['escape']),
|
||||
'sortable' => $element['sortable'] ?? current($element) != '',
|
||||
'checkbox' => $element['checkbox'] ?? false,
|
||||
'class' => isset($element['checkbox']) || preg_match('(^$| )', current($element)) ? 'print_hide' : '',
|
||||
@@ -470,7 +470,8 @@ function get_item_data_row(object $item): array
|
||||
: glob("./uploads/item_pics/$item->pic_filename");
|
||||
|
||||
if (sizeof($images) > 0) {
|
||||
$image .= '<a class="rollover" href="' . base_url($images[0]) . '"><img alt="Image thumbnail" src="' . site_url('items/PicThumb/' . pathinfo($images[0], PATHINFO_BASENAME)) . '"></a>';
|
||||
$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>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ 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" => "اللغة",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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" => "تم استيراد الأصناف بنجاح.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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" => "اللغة",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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" => "تم استيراد الأصناف بنجاح.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "Текущата парола е невалидна.",
|
||||
"employee" => "Служител",
|
||||
"error_adding_updating" => "Добавянето или актуализирането на служителите е неуспешно.",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "Не може да изтриете Пробният Администратор.",
|
||||
"error_updating_demo_admin" => "Не може да промените Пробният Администратор.",
|
||||
"language" => "Език",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
'current_password_invalid' => "وشەی نهێنی ئێستا نادروستە.",
|
||||
'employee' => "فەرمانبەر",
|
||||
'error_adding_updating' => "زیادکردن یان نوێکردنەوەی کارمەند سەرکەوتوو نەبوو.",
|
||||
'error_deleting_admin' => "",
|
||||
'error_updating_admin' => "",
|
||||
'error_deleting_demo_admin' => "ناتوانیت بەکارهێنەری ئەدمینی تاقیکردنەوەیی بسڕیتەوە.",
|
||||
'error_updating_demo_admin' => "ناتوانیت بەکارهێنەری ئەدمین تاقیکردنەوەیی بگۆڕیت.",
|
||||
'language' => "زمان",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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 سەرکەوتوو بوو.",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "",
|
||||
"employee" => "",
|
||||
"error_adding_updating" => "",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "",
|
||||
"error_updating_demo_admin" => "",
|
||||
"language" => "",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ return [
|
||||
"cost_price_required" => "",
|
||||
"count" => "",
|
||||
"csv_import_failed" => "",
|
||||
"csv_import_invalid_location" => "",
|
||||
"csv_import_nodata_wrongformat" => "",
|
||||
"csv_import_partially_failed" => "",
|
||||
"csv_import_success" => "",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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" => "",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "",
|
||||
"employee" => "",
|
||||
"error_adding_updating" => "",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "",
|
||||
"error_updating_demo_admin" => "",
|
||||
"language" => "",
|
||||
|
||||
@@ -26,6 +26,7 @@ return [
|
||||
"cost_price_required" => "",
|
||||
"count" => "",
|
||||
"csv_import_failed" => "",
|
||||
"csv_import_invalid_location" => "",
|
||||
"csv_import_nodata_wrongformat" => "",
|
||||
"csv_import_partially_failed" => "",
|
||||
"csv_import_success" => "",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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" => "",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "گذرواژه فعلی نامعتبر است.",
|
||||
"employee" => "کارمند",
|
||||
"error_adding_updating" => "افزودن یا به روزرسانی کارکنان انجام نشد.",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "شما نمی توانید کاربر مدیر نسخه ی نمایشی را حذف کنید.",
|
||||
"error_updating_demo_admin" => "شما نمی توانید کاربر مدیر نسخه ی نمایشی را تغییر دهید.",
|
||||
"language" => "زبان",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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" => "وارد کردن سیاسوی مورد موفقیت آمیز است.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "הסיסמה הנוכחית אינה חוקית.",
|
||||
"employee" => "עובד",
|
||||
"error_adding_updating" => "הוספה או עדכון של עובד נכשלה.",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "לא ניתן למחוק את משתמש המנהל ההדגמה.",
|
||||
"error_updating_demo_admin" => "לא ניתן לשנות את משתמש המנהל ההדגמה.",
|
||||
"language" => "שפה",
|
||||
|
||||
@@ -26,6 +26,7 @@ return [
|
||||
"cost_price_required" => "מחיר סיטונאי הינו שדה חובה.",
|
||||
"count" => "עדכן מלאי",
|
||||
"csv_import_failed" => "ייבוא אקסל נכשל",
|
||||
"csv_import_invalid_location" => "",
|
||||
"csv_import_nodata_wrongformat" => "בקובץ שהועלה אין נתונים או פורמט שגוי.",
|
||||
"csv_import_partially_failed" => "ייבוא פריט הצליח עם מספר שגיאות:",
|
||||
"csv_import_success" => "ייבוא הפריט הצליח.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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" => "",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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" => "",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "",
|
||||
"employee" => "",
|
||||
"error_adding_updating" => "",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "",
|
||||
"error_updating_demo_admin" => "",
|
||||
"language" => "",
|
||||
|
||||
@@ -26,6 +26,7 @@ return [
|
||||
"cost_price_required" => "",
|
||||
"count" => "",
|
||||
"csv_import_failed" => "",
|
||||
"csv_import_invalid_location" => "",
|
||||
"csv_import_nodata_wrongformat" => "",
|
||||
"csv_import_partially_failed" => "",
|
||||
"csv_import_success" => "",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "ពាក្យសម្ងាត់បច្ចុប្បន្ន មិនត្រឹមត្រូវ។",
|
||||
"employee" => "បុគ្គលិក",
|
||||
"error_adding_updating" => "បន្ថែម ឬកែប្រែបុគ្គលិកមិនបានសំរេច។",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "អ្នកមិនអាចលុប គណនីសាកល្បង បានទេ។",
|
||||
"error_updating_demo_admin" => "អ្នកមិនអាចកែប្រែ គណនីសាកល្បងបានទេ។",
|
||||
"language" => "ភាសា",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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 បញ្ចូលបានសំរេច។",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "Password ປັດຈຸບັນບໍ່ຖືກຕ້ອງ.",
|
||||
"employee" => "ພະນັກງານ",
|
||||
"error_adding_updating" => "ເພີ່ມ ຫຼື ແກ້ໄຂ ພະນັກງານ ບໍ່ສຳເລັດ.",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "ທ່ານບໍ່ສາມາດລຶບບັນຊີທົດລອງຜູ້ດູແລລະບົບໄດ້.",
|
||||
"error_updating_demo_admin" => "ທ່ານບໍ່ສາມາດປ່ຽນແປງບັນຊີທົດລອງຜູ້ດູແລລະບົບໄດ້.",
|
||||
"language" => "ພາສາ",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "",
|
||||
"employee" => "",
|
||||
"error_adding_updating" => "",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "",
|
||||
"error_updating_demo_admin" => "",
|
||||
"language" => "",
|
||||
|
||||
@@ -26,6 +26,7 @@ return [
|
||||
"cost_price_required" => "",
|
||||
"count" => "",
|
||||
"csv_import_failed" => "",
|
||||
"csv_import_invalid_location" => "",
|
||||
"csv_import_nodata_wrongformat" => "",
|
||||
"csv_import_partially_failed" => "",
|
||||
"csv_import_success" => "",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "",
|
||||
"employee" => "",
|
||||
"error_adding_updating" => "",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "",
|
||||
"error_updating_demo_admin" => "",
|
||||
"language" => "",
|
||||
|
||||
@@ -26,6 +26,7 @@ return [
|
||||
"cost_price_required" => "",
|
||||
"count" => "",
|
||||
"csv_import_failed" => "",
|
||||
"csv_import_invalid_location" => "",
|
||||
"csv_import_nodata_wrongformat" => "",
|
||||
"csv_import_partially_failed" => "",
|
||||
"csv_import_success" => "",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "",
|
||||
"employee" => "",
|
||||
"error_adding_updating" => "",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "",
|
||||
"error_updating_demo_admin" => "",
|
||||
"language" => "",
|
||||
|
||||
@@ -26,6 +26,7 @@ return [
|
||||
"cost_price_required" => "",
|
||||
"count" => "",
|
||||
"csv_import_failed" => "",
|
||||
"csv_import_invalid_location" => "",
|
||||
"csv_import_nodata_wrongformat" => "",
|
||||
"csv_import_partially_failed" => "",
|
||||
"csv_import_success" => "",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "",
|
||||
"employee" => "",
|
||||
"error_adding_updating" => "",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "",
|
||||
"error_updating_demo_admin" => "",
|
||||
"language" => "",
|
||||
|
||||
@@ -26,6 +26,7 @@ return [
|
||||
"cost_price_required" => "",
|
||||
"count" => "",
|
||||
"csv_import_failed" => "",
|
||||
"csv_import_invalid_location" => "",
|
||||
"csv_import_nodata_wrongformat" => "",
|
||||
"csv_import_partially_failed" => "",
|
||||
"csv_import_success" => "",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "Текущий пароль введен неверно.",
|
||||
"employee" => "Сотрудник",
|
||||
"error_adding_updating" => "Ошибка при добавлении/обновлении сотрудника.",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "Вы не можете удалить демо-администратора.",
|
||||
"error_updating_demo_admin" => "Вы не можете изменить демо-администратора.",
|
||||
"language" => "Язык",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "รหัสผ่านปัจจุบันไม่ถูกต้อง",
|
||||
"employee" => "พนักงาน",
|
||||
"error_adding_updating" => "การเพิ่มหรือปรับปรุงข้อมูลพนักงานผิดพลาด",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "คุณไม่สามารถลบผู้ใช้งานสำหรับการเดโม้ได้",
|
||||
"error_updating_demo_admin" => "คุณไม่สามารถทำการเปลี่ยนข้อมูลผู้ใช้งานเดโม้ได้",
|
||||
"language" => "ภาษา",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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ı.",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "Поточний пароль невірний.",
|
||||
"employee" => "Працівник",
|
||||
"error_adding_updating" => "Помилка при додаванні/оновлені працівника.",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "Ви не можете видалити аккаунт користувача.",
|
||||
"error_updating_demo_admin" => "Ви не можете змінити аккаунт користувача.",
|
||||
"language" => "Мова",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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 успішний.",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "",
|
||||
"employee" => "",
|
||||
"error_adding_updating" => "",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "",
|
||||
"error_updating_demo_admin" => "",
|
||||
"language" => "",
|
||||
|
||||
@@ -26,6 +26,7 @@ return [
|
||||
"cost_price_required" => "",
|
||||
"count" => "",
|
||||
"csv_import_failed" => "",
|
||||
"csv_import_invalid_location" => "",
|
||||
"csv_import_nodata_wrongformat" => "",
|
||||
"csv_import_partially_failed" => "",
|
||||
"csv_import_success" => "",
|
||||
|
||||
@@ -14,6 +14,8 @@ return [
|
||||
"current_password_invalid" => "Mật khẩu hiện tại không hợp lệ.",
|
||||
"employee" => "Nhân viên",
|
||||
"error_adding_updating" => "Gặp lỗi khi cập nhật hay thêm nhân viên.",
|
||||
"error_deleting_admin" => "",
|
||||
"error_updating_admin" => "",
|
||||
"error_deleting_demo_admin" => "Bạn không thể xóa người dùng demo admin.",
|
||||
"error_updating_demo_admin" => "Bạn không thể thay đổi người dùng demo admin.",
|
||||
"language" => "Ngôn ngữ",
|
||||
|
||||
@@ -26,6 +26,7 @@ return [
|
||||
"cost_price_required" => "Trường Giá bán buôn là bắt buộc.",
|
||||
"count" => "Cập hàng tồn kho",
|
||||
"csv_import_failed" => "Gặp lỗi khi nhập từ CSV",
|
||||
"csv_import_invalid_location" => "",
|
||||
"csv_import_nodata_wrongformat" => "Tập tin tải lên không có dữ liệu hoặc là nó có định dạng không đúng.",
|
||||
"csv_import_partially_failed" => "Có {0} mục tin gặp lỗi khi nhập trên dòng: {1}. Không có hàng nào được nhập vào.",
|
||||
"csv_import_success" => "Nhập hàng hóa thành công.",
|
||||
|
||||
@@ -14,6 +14,8 @@ 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" => "",
|
||||
|
||||
@@ -26,6 +26,7 @@ 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" => "Most Items imported. But some were not, here is the list",
|
||||
"csv_import_success" => "Import of Items successful",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user