mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-05-25 08:44:42 -04:00
Compare commits
69 Commits
feature/pa
...
feature/pa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d8e2442b5 | ||
|
|
56670271d6 | ||
|
|
cef103445e | ||
|
|
68e9a56632 | ||
|
|
ba05536317 | ||
|
|
f74f286a51 | ||
|
|
7180ec33e8 | ||
|
|
496c8a8262 | ||
|
|
493d9cc9c1 | ||
|
|
f761e1464f | ||
|
|
a5bbb2bcc5 | ||
|
|
92ec321d08 | ||
|
|
e046e74c79 | ||
|
|
e0cd0f6129 | ||
|
|
3b102adf3f | ||
|
|
260358d611 | ||
|
|
e615200466 | ||
|
|
56cead478a | ||
|
|
7030f6bac3 | ||
|
|
299f62669a | ||
|
|
072865620a | ||
|
|
3bbd4c4c95 | ||
|
|
0253bf85b8 | ||
|
|
92c1be8bb1 | ||
|
|
23829eab35 | ||
|
|
c81c6506cb | ||
|
|
840d9ccc81 | ||
|
|
e763ee2acc | ||
|
|
8ef109efbc | ||
|
|
9a544096c2 | ||
|
|
3e4ac0b24d | ||
|
|
3c9c592ca3 | ||
|
|
a4d8bedbf3 | ||
|
|
c4304fd0a9 | ||
|
|
44fe2c087a | ||
|
|
985c1c55ce | ||
|
|
8029e5538f | ||
|
|
1a7683a8ac | ||
|
|
e4b92b58c3 | ||
|
|
dc1e448bc3 | ||
|
|
24b2825b31 | ||
|
|
38d672592b | ||
|
|
6f7e06e986 | ||
|
|
fda40d9340 | ||
|
|
b49186ec7c | ||
|
|
8b56f61b8a | ||
|
|
9820beb0e1 | ||
|
|
e01dad728f | ||
|
|
234f930079 | ||
|
|
3001dc0e17 | ||
|
|
3ba207e8b9 | ||
|
|
d684c49ebd | ||
|
|
071e641f95 | ||
|
|
48af67bd00 | ||
|
|
7cb1d95da7 | ||
|
|
bafe3ddf1b | ||
|
|
c482e75304 | ||
|
|
afc2f82dc6 | ||
|
|
ce411707b4 | ||
|
|
37c6e22fc4 | ||
|
|
3c7ece5c33 | ||
|
|
02fccaf43f | ||
|
|
ee4d44ed39 | ||
|
|
fa3f257e7b | ||
|
|
431a9951e9 | ||
|
|
f7e8d6e427 | ||
|
|
85889b6e65 | ||
|
|
6818f02ef9 | ||
|
|
436696b11b |
@@ -1,23 +1,56 @@
|
||||
node_modules
|
||||
tmp
|
||||
# Version control
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Sensitive config (user may mount their own)
|
||||
app/Config/Email.php
|
||||
|
||||
# Build artifacts
|
||||
node_modules/
|
||||
dist/
|
||||
tmp/
|
||||
*.patch
|
||||
patches/
|
||||
|
||||
# IDE and editor files
|
||||
.idea/
|
||||
git-svn-diff.py
|
||||
*.bash
|
||||
.vscode/
|
||||
.swp
|
||||
*.swp
|
||||
.buildpath
|
||||
.project
|
||||
.settings/*
|
||||
.git
|
||||
dist/
|
||||
node_modules/
|
||||
*.swp
|
||||
.settings/
|
||||
|
||||
# Development tools and configs
|
||||
tests/
|
||||
phpunit.xml
|
||||
.php-cs-fixer.*
|
||||
phpstan.neon
|
||||
*.bash
|
||||
git-svn-diff.py
|
||||
|
||||
# Documentation
|
||||
*.md
|
||||
!LICENSE
|
||||
branding/
|
||||
|
||||
# Build configs (not needed at runtime)
|
||||
composer.json
|
||||
composer.lock
|
||||
package.json
|
||||
package-lock.json
|
||||
gulpfile.js
|
||||
.env.example
|
||||
.dockerignore
|
||||
|
||||
# Temporary and backup files
|
||||
*.rej
|
||||
*.orig
|
||||
*~
|
||||
*.~
|
||||
*.log
|
||||
app/writable/session/*
|
||||
!app/writable/session/index.html
|
||||
|
||||
# CI
|
||||
.github/
|
||||
.github/workflows/
|
||||
build/
|
||||
|
||||
29
.env.example
29
.env.example
@@ -4,6 +4,35 @@
|
||||
|
||||
CI_ENVIRONMENT = production
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# SECURITY: ALLOWED HOSTNAMES
|
||||
#--------------------------------------------------------------------
|
||||
# IMPORTANT: Whitelist of allowed hostnames to prevent Host Header
|
||||
# Injection attacks (GHSA-jchf-7hr6-h4f3).
|
||||
#
|
||||
# If not configured, the application will default to 'localhost',
|
||||
# which may break functionality in production.
|
||||
#
|
||||
# Configure this with all domains/subdomains that host your application:
|
||||
# - Primary domain
|
||||
# - WWW subdomain (if used)
|
||||
# - Any alternative domains
|
||||
#
|
||||
# Examples:
|
||||
# Single domain:
|
||||
# app.allowedHostnames.0 = 'example.com'
|
||||
#
|
||||
# Multiple domains:
|
||||
# app.allowedHostnames.0 = 'example.com'
|
||||
# app.allowedHostnames.1 = 'www.example.com'
|
||||
# app.allowedHostnames.2 = 'demo.opensourcepos.org'
|
||||
#
|
||||
# For localhost development:
|
||||
# app.allowedHostnames.0 = 'localhost'
|
||||
#
|
||||
# Note: Do not include the protocol (http/https) or port number.
|
||||
#app.allowedHostnames.0 = ''
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# DATABASE
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
61
.github/workflows/README.md
vendored
Normal file
61
.github/workflows/README.md
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
# GitHub Actions
|
||||
|
||||
This document describes the CI/CD workflows for OSPOS.
|
||||
|
||||
## Build and Release Workflow (`.github/workflows/build-release.yml`)
|
||||
|
||||
### Build Process
|
||||
- Setup PHP 8.2 with required extensions
|
||||
- Setup Node.js 20
|
||||
- Install composer dependencies
|
||||
- Install npm dependencies
|
||||
- Build frontend assets with Gulp
|
||||
|
||||
### Docker Images
|
||||
- Build and push `opensourcepos` Docker image for multiple architectures (linux/amd64, linux/arm64)
|
||||
- On master: tagged with version and `latest`
|
||||
- On other branches: tagged with version only
|
||||
- Pushed to Docker Hub
|
||||
|
||||
### Releases
|
||||
- Create distribution archives (tar.gz, zip)
|
||||
- Create/update GitHub "unstable" release on master branch only
|
||||
|
||||
## Required Secrets
|
||||
|
||||
To use this workflow, you need to add the following secrets to your repository:
|
||||
|
||||
1. **DOCKER_USERNAME** - Docker Hub username for pushing images
|
||||
2. **DOCKER_PASSWORD** - Docker Hub password/token for pushing images
|
||||
|
||||
### How to add secrets
|
||||
|
||||
1. Go to your repository on GitHub
|
||||
2. Click **Settings** → **Secrets and variables** → **Actions**
|
||||
3. Click **New repository secret**
|
||||
4. Add `DOCKER_USERNAME` and `DOCKER_PASSWORD`
|
||||
|
||||
The `GITHUB_TOKEN` is automatically provided by GitHub Actions.
|
||||
|
||||
## Workflow Triggers
|
||||
|
||||
- **Push to master** - Runs build, Docker push (with `latest` tag), and release
|
||||
- **Push to other branches** - Runs build and Docker push (version tag only)
|
||||
- **Push tags** - Runs build and Docker push (version tag only)
|
||||
- **Pull requests** - Runs build only (PHPUnit tests run in parallel via phpunit.yml)
|
||||
|
||||
## Existing Workflows
|
||||
|
||||
This repository also has these workflows:
|
||||
- `.github/workflows/main.yml` - PHP linting with PHP-CS-Fixer
|
||||
- `.github/workflows/phpunit.yml` - PHPUnit tests (runs on all PHP versions 8.1-8.4)
|
||||
- `.github/workflows/php-linter.yml` - PHP linting
|
||||
|
||||
## Testing
|
||||
|
||||
PHPUnit tests are run separately via `.github/workflows/phpunit.yml` on every push and pull request, testing against PHP 8.1, 8.2, 8.3, and 8.4.
|
||||
|
||||
To test the build workflow:
|
||||
1. Add the required secrets
|
||||
2. Push to master or create a PR
|
||||
3. Monitor the Actions tab in GitHub
|
||||
218
.github/workflows/build-release.yml
vendored
Normal file
218
.github/workflows/build-release.yml
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
name: Build and Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
version-tag: ${{ steps.version.outputs.version-tag }}
|
||||
short-sha: ${{ steps.version.outputs.short-sha }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.2'
|
||||
extensions: intl, mbstring, mysqli, gd, bcmath, zip
|
||||
coverage: none
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Get composer cache directory
|
||||
run: echo "COMPOSER_CACHE_FILES_DIR=$(composer config cache-files-dir)" >> $GITHUB_ENV
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.COMPOSER_CACHE_FILES_DIR }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-composer-
|
||||
|
||||
- name: Get npm cache directory
|
||||
run: echo "NPM_CACHE_DIR=$(npm config get cache)" >> $GITHUB_ENV
|
||||
|
||||
- name: Cache npm dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.NPM_CACHE_DIR }}
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- name: Install composer dependencies
|
||||
run: composer install --no-dev --optimize-autoloader
|
||||
|
||||
- name: Install npm dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Install gulp globally
|
||||
run: npm install -g gulp-cli
|
||||
|
||||
- name: Get version info
|
||||
id: version
|
||||
run: |
|
||||
VERSION=$(grep "application_version" app/Config/App.php | sed "s/.*= '\(.*\)';/\1/g")
|
||||
BRANCH=$(echo "${GITHUB_REF#refs/heads/}" | sed 's/feature\///')
|
||||
TAG=$(echo "${GITHUB_TAG:-$BRANCH}" | tr '/' '-')
|
||||
SHORT_SHA=$(git rev-parse --short=6 HEAD)
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "version-tag=$VERSION-$BRANCH-$SHORT_SHA" >> $GITHUB_OUTPUT
|
||||
echo "short-sha=$SHORT_SHA" >> $GITHUB_OUTPUT
|
||||
echo "branch=$BRANCH" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
GITHUB_TAG: ${{ github.ref_name }}
|
||||
|
||||
- name: Create .env file
|
||||
run: |
|
||||
cp .env.example .env
|
||||
sed -i 's/production/development/g' .env
|
||||
|
||||
- name: Update commit hash
|
||||
run: |
|
||||
SHORT_SHA="${{ steps.version.outputs.short-sha }}"
|
||||
sed -i "s/commit_sha1 = 'dev'/commit_sha1 = '$SHORT_SHA'/g" app/Config/OSPOS.php
|
||||
|
||||
- name: Build frontend assets
|
||||
run: npm run build
|
||||
|
||||
- name: Create distribution archives
|
||||
run: |
|
||||
set -euo pipefail
|
||||
gulp compress
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
SHORT_SHA="${{ steps.version.outputs.short-sha }}"
|
||||
mv dist/opensourcepos.tar "dist/opensourcepos.$VERSION.$SHORT_SHA.tar"
|
||||
mv dist/opensourcepos.zip "dist/opensourcepos.$VERSION.$SHORT_SHA.zip"
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: dist-${{ steps.version.outputs.short-sha }}
|
||||
path: dist/
|
||||
retention-days: 7
|
||||
|
||||
- name: Upload build context for Docker
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-context-${{ steps.version.outputs.short-sha }}
|
||||
path: |
|
||||
.
|
||||
!.git
|
||||
!node_modules
|
||||
retention-days: 1
|
||||
|
||||
docker:
|
||||
name: Build Docker Image
|
||||
runs-on: ubuntu-22.04
|
||||
needs: build
|
||||
if: github.event_name == 'push'
|
||||
|
||||
steps:
|
||||
- name: Download build context
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: build-context-${{ needs.build.outputs.short-sha }}
|
||||
path: .
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Determine Docker tags
|
||||
id: tags
|
||||
run: |
|
||||
BRANCH=$(echo "${GITHUB_REF#refs/heads/}" | tr '/' '-')
|
||||
if [ "$BRANCH" = "master" ]; then
|
||||
echo "tags=${{ secrets.DOCKER_USERNAME }}/opensourcepos:${{ needs.build.outputs.version-tag }},${{ secrets.DOCKER_USERNAME }}/opensourcepos:latest" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "tags=${{ secrets.DOCKER_USERNAME }}/opensourcepos:${{ needs.build.outputs.version-tag }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
env:
|
||||
GITHUB_REF: ${{ github.ref }}
|
||||
|
||||
- name: Build and push Docker images
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
target: ospos
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.tags.outputs.tags }}
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
needs: build
|
||||
runs-on: ubuntu-22.04
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: dist-${{ needs.build.outputs.short-sha }}
|
||||
path: dist/
|
||||
|
||||
- name: Get version info
|
||||
id: version
|
||||
run: |
|
||||
VERSION="${{ needs.build.outputs.version }}"
|
||||
SHORT_SHA=$(git rev-parse --short=6 HEAD)
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "short-sha=$SHORT_SHA" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create/Update unstable release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: unstable
|
||||
name: Unstable OpenSourcePOS
|
||||
body: |
|
||||
This is a build of the latest master which might contain bugs. Use at your own risk.
|
||||
|
||||
Check the releases section for the latest official release.
|
||||
files: |
|
||||
dist/opensourcepos.${{ steps.version.outputs.version }}.${{ steps.version.outputs.short-sha }}.zip
|
||||
prerelease: true
|
||||
draft: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
71
.github/workflows/codeql-analysis.yml
vendored
71
.github/workflows/codeql-analysis.yml
vendored
@@ -1,71 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '21 12 * * 3'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
4
.github/workflows/phpunit.yml
vendored
4
.github/workflows/phpunit.yml
vendored
@@ -69,9 +69,6 @@ jobs:
|
||||
- name: Install npm dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Build database.sql
|
||||
run: npm run gulp build-database
|
||||
|
||||
- name: Start MariaDB
|
||||
run: |
|
||||
docker run -d --name mysql \
|
||||
@@ -79,7 +76,6 @@ jobs:
|
||||
-e MYSQL_DATABASE=ospos \
|
||||
-e MYSQL_USER=admin \
|
||||
-e MYSQL_PASSWORD=pointofsale \
|
||||
-v $PWD/app/Database/database.sql:/docker-entrypoint-initdb.d/database.sql \
|
||||
-p 3306:3306 \
|
||||
mariadb:10.5
|
||||
# Wait for MariaDB to be ready
|
||||
|
||||
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
|
||||
54
.travis.yml
54
.travis.yml
@@ -1,54 +0,0 @@
|
||||
sudo: required
|
||||
|
||||
branches:
|
||||
except:
|
||||
- unstable
|
||||
- weblate
|
||||
services:
|
||||
- docker
|
||||
|
||||
dist: jammy
|
||||
language: node_js
|
||||
node_js:
|
||||
- 20
|
||||
script:
|
||||
- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
- docker run --rm -u $(id -u) -v $(pwd):/app opensourcepos/composer:ci4 composer install
|
||||
- version=$(grep application_version app/Config/App.php | sed "s/.*=\s'\(.*\)';/\1/g")
|
||||
- cp .env.example .env && sed -i 's/production/development/g' .env
|
||||
- sed -i "s/commit_sha1 = 'dev'/commit_sha1 = '$rev'/g" app/Config/OSPOS.php
|
||||
- echo "$version-$branch-$rev"
|
||||
- npm version "$version-$branch-$rev" --force || true
|
||||
- sed -i 's/opensourcepos.tar.gz/opensourcepos.$version.tgz/g' package.json
|
||||
- npm ci && npm install -g gulp && npm run build
|
||||
- docker build . --target ospos -t ospos
|
||||
- docker build . --target ospos_test -t ospos_test
|
||||
- docker run --rm ospos_test /app/vendor/bin/phpunit --testdox
|
||||
- docker build app/Database/ -t "jekkos/opensourcepos:sql-$TAG"
|
||||
env:
|
||||
global:
|
||||
- BRANCH=$(echo ${TRAVIS_BRANCH} | sed s/feature\\///)
|
||||
- TAG=$(echo "${TRAVIS_TAG:-$BRANCH}" | tr '/' '-')
|
||||
- date=`date +%Y%m%d%H%M%S` && branch=${TRAVIS_BRANCH} && rev=`git rev-parse --short=6 HEAD`
|
||||
after_success:
|
||||
- docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD" && docker tag "ospos:latest"
|
||||
"jekkos/opensourcepos:$TAG" && docker push "jekkos/opensourcepos:$TAG" && docker push "jekkos/opensourcepos:sql-$TAG"
|
||||
- gulp compress
|
||||
- mv dist/opensourcepos.tar.gz "dist/opensourcepos.$version.$rev.tgz"
|
||||
- mv dist/opensourcepos.zip "dist/opensourcepos.$version.$rev.zip"
|
||||
deploy:
|
||||
- provider: releases
|
||||
edge: true
|
||||
file: dist/opensourcepos.$version.$rev.zip
|
||||
name: "Unstable OpensourcePos"
|
||||
overwrite: true
|
||||
release_notes: "This is a build of the latest master which might contain bugs. Use at your own risk. Check releases section for the latest official release"
|
||||
prerelease: true
|
||||
tag_name: unstable
|
||||
user: jekkos
|
||||
|
||||
api_key:
|
||||
secure: "KOukL8IFf/uL/BjMyCSKjf2vylydjcWqgEx0eMqFCg3nZ4ybMaOwPORRthIfyT72/FvGX/aoxxEn0uR/AEtb+hYQXHmNS+kZdX72JCe8LpGuZ7FJ5X+Eo9mhJcsmS+smd1sC95DySSc/GolKPo+0WtJYONY/xGCLxm+9Ay4HREg="
|
||||
|
||||
on:
|
||||
branch: master
|
||||
40
AGENTS.md
Normal file
40
AGENTS.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Agent Instructions
|
||||
|
||||
This document provides guidance for AI agents working on the Open Source Point of Sale (OSPOS) codebase.
|
||||
|
||||
## Code Style
|
||||
|
||||
- Follow PHP CodeIgniter 4 coding standards
|
||||
- Run PHP-CS-Fixer before committing: `vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.no-header.php`
|
||||
- Write PHP 8.1+ compatible code with proper type declarations
|
||||
- Use PSR-12 naming conventions: `camelCase` for variables and functions, `PascalCase` for classes, `UPPER_CASE` for constants
|
||||
|
||||
## Development
|
||||
|
||||
- Create a new git worktree for each issue, based on the latest state of `origin/master`
|
||||
- Commit fixes to the worktree and push to the remote
|
||||
|
||||
## Testing
|
||||
|
||||
- Run PHPUnit tests: `composer test`
|
||||
- Tests must pass before submitting changes
|
||||
|
||||
## Build
|
||||
|
||||
- Install dependencies: `composer install && npm install`
|
||||
- Build assets: `npm run build` or `gulp`
|
||||
|
||||
## Conventions
|
||||
|
||||
- Controllers go in `app/Controllers/`
|
||||
- Models go in `app/Models/`
|
||||
- Views go in `app/Views/`
|
||||
- Database migrations in `app/Database/Migrations/`
|
||||
- Use CodeIgniter 4 framework patterns and helpers
|
||||
- Sanitize user input; escape output using `esc()` helper
|
||||
|
||||
## Security
|
||||
|
||||
- Never commit secrets, credentials, or `.env` files
|
||||
- Use parameterized queries to prevent SQL injection
|
||||
- Validate and sanitize all user input
|
||||
32
Dockerfile
32
Dockerfile
@@ -1,28 +1,22 @@
|
||||
FROM php:8.2-apache AS ospos
|
||||
LABEL maintainer="jekkos"
|
||||
|
||||
RUN apt update && apt-get install -y libicu-dev libgd-dev
|
||||
RUN a2enmod rewrite
|
||||
RUN docker-php-ext-install mysqli bcmath intl gd
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libicu-dev \
|
||||
libgd-dev \
|
||||
&& docker-php-ext-install mysqli bcmath intl gd \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& a2enmod rewrite
|
||||
|
||||
RUN echo "date.timezone = \"\${PHP_TIMEZONE}\"" > /usr/local/etc/php/conf.d/timezone.ini
|
||||
|
||||
WORKDIR /app
|
||||
COPY . /app
|
||||
RUN ln -s /app/*[^public] /var/www && rm -rf /var/www/html && ln -nsf /app/public /var/www/html
|
||||
RUN chmod -R 770 /app/writable/uploads /app/writable/logs /app/writable/cache && chown -R www-data:www-data /app
|
||||
|
||||
FROM ospos AS ospos_test
|
||||
|
||||
COPY --from=composer /usr/bin/composer /usr/bin/composer
|
||||
|
||||
RUN apt-get install -y libzip-dev wget git
|
||||
RUN wget https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh -O /bin/wait-for-it.sh && chmod +x /bin/wait-for-it.sh
|
||||
RUN docker-php-ext-install zip
|
||||
RUN composer install -d/app
|
||||
#RUN sed -i 's/backupGlobals="true"/backupGlobals="false"/g' /app/tests/phpunit.xml
|
||||
WORKDIR /app/tests
|
||||
|
||||
CMD ["/app/vendor/phpunit/phpunit/phpunit", "/app/test/helpers"]
|
||||
COPY --chown=www-data:www-data . /app
|
||||
RUN chmod 770 /app/writable/uploads /app/writable/logs /app/writable/cache \
|
||||
&& ln -s /app/*[^public] /var/www \
|
||||
&& rm -rf /var/www/html \
|
||||
&& ln -nsf /app/public /var/www/html
|
||||
|
||||
FROM ospos AS ospos_dev
|
||||
|
||||
|
||||
3
Dockerfile.test
Normal file
3
Dockerfile.test
Normal file
@@ -0,0 +1,3 @@
|
||||
FROM php:8.4-cli
|
||||
RUN apt-get update && apt-get install -y libicu-dev && docker-php-ext-install intl
|
||||
WORKDIR /app
|
||||
43
INSTALL.md
43
INSTALL.md
@@ -6,22 +6,53 @@
|
||||
- Raspberry PI based installations proved to work, see [wiki page here](<https://github.com/opensourcepos/opensourcepos/wiki/Installing-on-Raspberry-PI---Orange-PI-(Headless-OSPOS)>).
|
||||
- For Windows based installations please read [the wiki](https://github.com/opensourcepos/opensourcepos/wiki). There are closed issues about this subject, as this topic has been covered a lot.
|
||||
|
||||
## Security Configuration
|
||||
|
||||
### Allowed Hostnames (Required for Production)
|
||||
|
||||
OpenSourcePOS validates the Host header against a whitelist to prevent Host Header Injection attacks (GHSA-jchf-7hr6-h4f3). **You must configure this for production deployments.**
|
||||
|
||||
Add the following to your `.env` file:
|
||||
|
||||
```
|
||||
app.allowedHostnames.0 = 'yourdomain.com'
|
||||
app.allowedHostnames.1 = 'www.yourdomain.com'
|
||||
```
|
||||
|
||||
**For local development**, use:
|
||||
```
|
||||
app.allowedHostnames.0 = 'localhost'
|
||||
```
|
||||
|
||||
If `allowedHostnames` is not configured:
|
||||
1. A security warning will be logged
|
||||
2. The application will fall back to 'localhost' as the hostname
|
||||
3. This means URLs generated by the application (links, redirects, etc.) will point to 'localhost'
|
||||
|
||||
### HTTPS Behind Proxy
|
||||
|
||||
If your installation is behind a proxy with SSL offloading, set:
|
||||
```
|
||||
FORCE_HTTPS = true
|
||||
```
|
||||
|
||||
## Local install
|
||||
|
||||
First of all, if you're seeing the message `system folder missing` after launching your browser, or cannot find `database.sql`, that most likely means you have cloned the repository and have not built the project. To build the project from a source commit point instead of from an official release check out [Building OSPOS](BUILD.md). Otherwise, continue with the following steps.
|
||||
First of all, if you're seeing the message `system folder missing` after launching your browser, that most likely means you have cloned the repository and have not built the project. To build the project from a source commit point instead of from an official release check out [Building OSPOS](BUILD.md). Otherwise, continue with the following steps.
|
||||
|
||||
1. Download the a [pre-release for a specific branch](https://github.com/opensourcepos/opensourcepos/releases) or the latest stable [from GitHub here](https://github.com/opensourcepos/opensourcepos/releases). A repository clone will not work unless know how to build the project.
|
||||
2. Create/locate a new MySQL database to install Open Source Point of Sale into.
|
||||
3. Execute the file `app/Database/database.sql` to create the tables needed.
|
||||
4. Unzip and upload Open Source Point of Sale files to the web-server.
|
||||
5. Open `.env` file and modify credentials to connect to your database if needed. (First copy .env.example to .env and update)
|
||||
3. Unzip and upload Open Source Point of Sale files to the web-server.
|
||||
4. If `.env` does not exist, copy `.env.example` to `.env`.
|
||||
5. Open `.env` and modify credentials to connect to your database if needed.
|
||||
6. The database schema will be automatically created when you first access the application. Migrations run automatically on fresh installs.
|
||||
7. Go to your install `public` dir via the browser.
|
||||
8. Log in using
|
||||
- Username: admin
|
||||
- Password: pointofsale
|
||||
9. If everything works, then set the `CI_ENVIRONMENT` variable to `production` in the .env file
|
||||
9. Enjoy!
|
||||
10. Oops, an issue? Please make sure you read the FAQ, wiki page, and you checked open and closed issues on GitHub. PHP `display_errors` is disabled by default. Create an` app/Config/.env` file from the `.env.example` to enable it in a development environment.
|
||||
10. Enjoy!
|
||||
11. Oops, an issue? Please make sure you read the FAQ, wiki page, and you checked open and closed issues on GitHub. PHP `display_errors` is disabled by default. Create an` app/Config/.env` file from the `.env.example` to enable it in a development environment.
|
||||
|
||||
## Local install using Docker
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://app.travis-ci.com/opensourcepos/opensourcepos" target="_blank"><img src="https://api.travis-ci.com/opensourcepos/opensourcepos.svg?branch=master" alt="Build Status"></a>
|
||||
<a href="https://github.com/opensourcepos/opensourcepos/actions/workflows/build-release.yml" target="_blank"><img src="https://github.com/opensourcepos/opensourcepos/actions/workflows/build-release.yml/badge.svg" alt="Build Status"></a>
|
||||
<a href="https://app.gitter.im/#/room/#opensourcepos_Lobby:gitter.im?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge" target="_blank"><img src="https://badges.gitter.im/jekkos/opensourcepos.svg" alt="Join the chat at https://app.gitter.im"></a>
|
||||
<a href="https://badge.fury.io/gh/opensourcepos%2Fopensourcepos" target="_blank"><img src="https://badge.fury.io/gh/opensourcepos%2Fopensourcepos.svg" alt="Project Version"></a>
|
||||
<a href="https://translate.opensourcepos.org/engage/opensourcepos/?utm_source=widget" target="_blank"><img src="https://translate.opensourcepos.org/widgets/opensourcepos/-/svg-badge.svg" alt="Translation Status"></a>
|
||||
@@ -137,7 +137,7 @@ Any person or company found breaching the license agreement might find a bunch o
|
||||
|
||||
## 🙏 Credits
|
||||
|
||||
| <div align="center">DigitalOcean</div> | <div align="center">JetBrains</div> | <div align="center">Travis CI</div> |
|
||||
| <div align="center">DigitalOcean</div> | <div align="center">JetBrains</div> | <div align="center">GitHub</div> |
|
||||
| --- | --- | --- |
|
||||
| <div align="center"><a href="https://www.digitalocean.com?utm_medium=opensource&utm_source=opensourcepos" target="_blank"><img src="https://github.com/user-attachments/assets/fbbf7433-ed35-407d-8946-fd03d236d350" alt="DigitalOcean Logo" height="50"></a></div> | <div align="center"><a href="https://www.jetbrains.com/idea/" target="_blank"><img src="https://github.com/opensourcepos/opensourcepos/assets/12870258/187f9bbe-4484-475c-9b58-5e5d5f931f09" alt="IntelliJ IDEA Logo" height="50"></a></div> | <div align="center"><a href="https://www.travis-ci.com/" target="_blank"><img src="https://github.com/opensourcepos/opensourcepos/assets/12870258/71cc2b44-83af-4510-a543-6358285f43c6" alt="Travis CI Logo" height="50"></a></div> |
|
||||
| Many thanks to [DigitalOcean](https://www.digitalocean.com) for providing the project with hosting credits. | Many thanks to [JetBrains](https://www.jetbrains.com/) for providing a free license of [IntelliJ IDEA](https://www.jetbrains.com/idea/) to kindly support the development of OSPOS. | Many thanks to [Travis CI](https://www.travis-ci.com/) for providing a free continuous integration service for open source projects. |
|
||||
| <div align="center"><a href="https://www.digitalocean.com?utm_medium=opensource&utm_source=opensourcepos" target="_blank"><img src="https://github.com/user-attachments/assets/fbbf7433-ed35-407d-8946-fd03d236d350" alt="DigitalOcean Logo" height="50"></a></div> | <div align="center"><a href="https://www.jetbrains.com/idea/" target="_blank"><img src="https://github.com/opensourcepos/opensourcepos/assets/12870258/187f9bbe-4484-475c-9b58-5e5d5f931f09" alt="IntelliJ IDEA Logo" height="50"></a></div> | <div align="center"><a href="https://github.com/features/actions" target="_blank"><img src="https://github.githubassets.com/images/modules/site/icons/eyebrow-panel/actions-icon.svg" alt="GitHub Actions Logo" height="50"></a></div> |
|
||||
| Many thanks to [DigitalOcean](https://www.digitalocean.com) for providing the project with hosting credits. | Many thanks to [JetBrains](https://www.jetbrains.com/) for providing a free license of [IntelliJ IDEA](https://www.jetbrains.com/idea/) to kindly support the development of OSPOS. | Many thanks to [GitHub](https://github.com) for providing free continuous integration via GitHub Actions for open-source projects. |
|
||||
|
||||
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.
|
||||
@@ -55,13 +55,21 @@ class App extends BaseConfig
|
||||
public string $baseURL; // Defined in the constructor
|
||||
|
||||
/**
|
||||
* Allowed Hostnames in the Site URL other than the hostname in the baseURL.
|
||||
* If you want to accept multiple Hostnames, set this.
|
||||
*
|
||||
* E.g.,
|
||||
* When your site URL ($baseURL) is 'http://example.com/', and your site
|
||||
* also accepts 'http://media.example.com/' and 'http://accounts.example.com/':
|
||||
* ['media.example.com', 'accounts.example.com']
|
||||
* Allowed Hostnames for the Site URL.
|
||||
*
|
||||
* Security: This is used to validate the HTTP Host header to prevent
|
||||
* Host Header Injection attacks. If the Host header doesn't match
|
||||
* an entry in this list, the request will use the first allowed hostname.
|
||||
*
|
||||
* IMPORTANT: This MUST be configured for production deployments.
|
||||
* If empty, the application will fall back to 'localhost'.
|
||||
*
|
||||
* Configure via .env file:
|
||||
* app.allowedHostnames.0 = 'example.com'
|
||||
* app.allowedHostnames.1 = 'www.example.com'
|
||||
*
|
||||
* For local development:
|
||||
* app.allowedHostnames.0 = 'localhost'
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
@@ -284,8 +292,44 @@ class App extends BaseConfig
|
||||
{
|
||||
parent::__construct();
|
||||
$this->https_on = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_ENV['FORCE_HTTPS']) && $_ENV['FORCE_HTTPS'] == 'true');
|
||||
|
||||
$host = $this->getValidHost();
|
||||
$this->baseURL = $this->https_on ? 'https' : 'http';
|
||||
$this->baseURL .= '://' . ((isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : 'localhost') . '/';
|
||||
$this->baseURL .= '://' . $host . '/';
|
||||
$this->baseURL .= str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and returns a trusted hostname.
|
||||
*
|
||||
* Security: Prevents Host Header Injection attacks (GHSA-jchf-7hr6-h4f3)
|
||||
* by validating the HTTP_HOST against a whitelist of allowed hostnames.
|
||||
*
|
||||
* @return string A validated hostname
|
||||
*/
|
||||
private function getValidHost(): string
|
||||
{
|
||||
$httpHost = $_SERVER['HTTP_HOST'] ?? 'localhost';
|
||||
|
||||
if (empty($this->allowedHostnames)) {
|
||||
log_message('warning',
|
||||
'Security: allowedHostnames is not configured. ' .
|
||||
'Host header injection protection is disabled. ' .
|
||||
'Please set app.allowedHostnames in your .env file. ' .
|
||||
'Received Host: ' . $httpHost
|
||||
);
|
||||
return 'localhost';
|
||||
}
|
||||
|
||||
if (in_array($httpHost, $this->allowedHostnames, true)) {
|
||||
return $httpHost;
|
||||
}
|
||||
|
||||
log_message('warning',
|
||||
'Security: Rejected HTTP_HOST "' . $httpHost . '" - not in allowedHostnames whitelist. ' .
|
||||
'Using fallback: ' . $this->allowedHostnames[0]
|
||||
);
|
||||
|
||||
return $this->allowedHostnames[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ $routes->get('/', 'Login::index');
|
||||
$routes->get('login', 'Login::index');
|
||||
$routes->post('login', 'Login::index');
|
||||
|
||||
// Payment provider webhook routes (no authentication required)
|
||||
$routes->post('payments/webhook/(:segment)', 'Payments\Webhook::handle/$1');
|
||||
$routes->get('payments/status/(:segment)/(:segment)', 'Payments\Webhook::status/$1/$2');
|
||||
|
||||
$routes->add('no_access/index/(:segment)', 'No_access::index/$1');
|
||||
$routes->add('no_access/index/(:segment)/(:segment)', 'No_access::index/$1/$2');
|
||||
|
||||
|
||||
@@ -106,12 +106,24 @@ class Attributes extends Secure_Controller
|
||||
$definition_flags |= $flag;
|
||||
}
|
||||
|
||||
// Validate definition_group (definition_fk) foreign key
|
||||
$definition_group_input = $this->request->getPost('definition_group');
|
||||
$definition_fk = $this->validateDefinitionGroup($definition_group_input);
|
||||
|
||||
if ($definition_fk === false) {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => lang('Attributes.definition_invalid_group'),
|
||||
'id' => NEW_ENTRY
|
||||
]);
|
||||
}
|
||||
|
||||
// Save definition data
|
||||
$definition_data = [
|
||||
'definition_name' => $this->request->getPost('definition_name'),
|
||||
'definition_unit' => $this->request->getPost('definition_unit') != '' ? $this->request->getPost('definition_unit') : null,
|
||||
'definition_flags' => $definition_flags,
|
||||
'definition_fk' => $this->request->getPost('definition_group') != '' ? $this->request->getPost('definition_group') : null
|
||||
'definition_fk' => $definition_fk
|
||||
];
|
||||
|
||||
if ($this->request->getPost('definition_type') != null) {
|
||||
@@ -150,6 +162,32 @@ class Attributes extends Secure_Controller
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a definition_group foreign key.
|
||||
* Returns the validated integer ID, null if empty, or false if invalid.
|
||||
*
|
||||
* @param mixed $definition_group_input
|
||||
* @return int|null|false
|
||||
*/
|
||||
private function validateDefinitionGroup(mixed $definition_group_input): int|null|false
|
||||
{
|
||||
if ($definition_group_input === '' || $definition_group_input === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$definition_group_id = (int) $definition_group_input;
|
||||
|
||||
// Must be a positive integer, exist in attribute_definitions, and be of type GROUP
|
||||
if ($definition_group_id <= 0
|
||||
|| !$this->attribute->exists($definition_group_id)
|
||||
|| $this->attribute->getAttributeInfo($definition_group_id)->definition_type !== GROUP
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $definition_group_id;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param int $definition_id
|
||||
|
||||
@@ -36,6 +36,9 @@ class Cashups extends Secure_Controller
|
||||
// filters that will be loaded in the multiselect dropdown
|
||||
$data['filters'] = ['is_deleted' => lang('Cashups.is_deleted')];
|
||||
|
||||
// Restore filters from URL
|
||||
$data = array_merge($data, restoreTableFilters($this->request));
|
||||
|
||||
return view('cashups/manage', $data);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ use App\Models\Appconfig;
|
||||
use App\Models\Attribute;
|
||||
use App\Models\Customer_rewards;
|
||||
use App\Models\Dinner_table;
|
||||
use App\Models\Item;
|
||||
use App\Models\Module;
|
||||
use App\Models\Enums\Rounding_mode;
|
||||
use App\Models\Stock_location;
|
||||
@@ -385,9 +386,9 @@ class Config extends Secure_Controller
|
||||
'gcaptcha_enable' => $this->request->getPost('gcaptcha_enable') != null,
|
||||
'gcaptcha_secret_key' => $this->request->getPost('gcaptcha_secret_key'),
|
||||
'gcaptcha_site_key' => $this->request->getPost('gcaptcha_site_key'),
|
||||
'suggestions_first_column' => $this->request->getPost('suggestions_first_column'),
|
||||
'suggestions_second_column' => $this->request->getPost('suggestions_second_column'),
|
||||
'suggestions_third_column' => $this->request->getPost('suggestions_third_column'),
|
||||
'suggestions_first_column' => $this->validateSuggestionsColumn($this->request->getPost('suggestions_first_column'), 'first'),
|
||||
'suggestions_second_column' => $this->validateSuggestionsColumn($this->request->getPost('suggestions_second_column'), 'other'),
|
||||
'suggestions_third_column' => $this->validateSuggestionsColumn($this->request->getPost('suggestions_third_column'), 'other'),
|
||||
'giftcard_number' => $this->request->getPost('giftcard_number'),
|
||||
'derive_sale_quantity' => $this->request->getPost('derive_sale_quantity') != null,
|
||||
'multi_pack_enabled' => $this->request->getPost('multi_pack_enabled') != null,
|
||||
@@ -976,4 +977,26 @@ class Config extends Secure_Controller
|
||||
|
||||
return $this->response->setJSON(['success' => $success]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates suggestions column configuration to prevent SQL injection.
|
||||
*
|
||||
* @param mixed $column The column value from POST
|
||||
* @param string $fieldType Either 'first' or 'other' to determine default fallback
|
||||
* @return string Validated column name
|
||||
*/
|
||||
private function validateSuggestionsColumn(mixed $column, string $fieldType): string
|
||||
{
|
||||
if (!is_string($column)) {
|
||||
return $fieldType === 'first' ? 'name' : '';
|
||||
}
|
||||
|
||||
$allowed = $fieldType === 'first'
|
||||
? Item::ALLOWED_SUGGESTIONS_COLUMNS
|
||||
: Item::ALLOWED_SUGGESTIONS_COLUMNS_WITH_EMPTY;
|
||||
|
||||
$fallback = $fieldType === 'first' ? 'name' : '';
|
||||
|
||||
return in_array($column, $allowed, true) ? $column : $fallback;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,9 @@ class Expenses extends Secure_Controller
|
||||
'is_deleted' => lang('Expenses.is_deleted')
|
||||
];
|
||||
|
||||
// Restore filters from URL
|
||||
$data = array_merge($data, restoreTableFilters($this->request));
|
||||
|
||||
return view('expenses/manage', $data);
|
||||
}
|
||||
|
||||
@@ -90,16 +93,23 @@ class Expenses extends Secure_Controller
|
||||
{
|
||||
$data = []; // TODO: Duplicated code
|
||||
|
||||
$data['employees'] = [];
|
||||
foreach ($this->employee->get_all()->getResult() as $employee) {
|
||||
foreach (get_object_vars($employee) as $property => $value) {
|
||||
$employee->$property = $value;
|
||||
}
|
||||
|
||||
$data['employees'][$employee->person_id] = $employee->first_name . ' ' . $employee->last_name;
|
||||
}
|
||||
|
||||
$data['expenses_info'] = $this->expense->get_info($expense_id);
|
||||
$expense_id = $data['expenses_info']->expense_id;
|
||||
|
||||
$current_employee_id = $this->employee->get_logged_in_employee_info()->person_id;
|
||||
$can_assign_employee = $this->employee->has_grant('employees', $current_employee_id);
|
||||
|
||||
$data['employees'] = [];
|
||||
if ($can_assign_employee) {
|
||||
foreach ($this->employee->get_all()->getResult() as $employee) {
|
||||
$data['employees'][$employee->person_id] = $employee->first_name . ' ' . $employee->last_name;
|
||||
}
|
||||
} else {
|
||||
$stored_employee_id = $expense_id == NEW_ENTRY ? $current_employee_id : $data['expenses_info']->employee_id;
|
||||
$stored_employee = $this->employee->get_info($stored_employee_id);
|
||||
$data['employees'][$stored_employee_id] = $stored_employee->first_name . ' ' . $stored_employee->last_name;
|
||||
}
|
||||
$data['can_assign_employee'] = $can_assign_employee;
|
||||
|
||||
$expense_categories = [];
|
||||
foreach ($this->expense_category->get_all(0, 0, true)->getResultArray() as $row) {
|
||||
@@ -107,11 +117,9 @@ class Expenses extends Secure_Controller
|
||||
}
|
||||
$data['expense_categories'] = $expense_categories;
|
||||
|
||||
$expense_id = $data['expenses_info']->expense_id;
|
||||
|
||||
if ($expense_id == NEW_ENTRY) {
|
||||
$data['expenses_info']->date = date('Y-m-d H:i:s');
|
||||
$data['expenses_info']->employee_id = $this->employee->get_logged_in_employee_info()->person_id;
|
||||
$data['expenses_info']->employee_id = $current_employee_id;
|
||||
}
|
||||
|
||||
$data['payments'] = [];
|
||||
@@ -152,6 +160,20 @@ class Expenses extends Secure_Controller
|
||||
|
||||
$date_formatter = date_create_from_format($config['dateformat'] . ' ' . $config['timeformat'], $newdate);
|
||||
|
||||
$current_employee_id = $this->employee->get_logged_in_employee_info()->person_id;
|
||||
$submitted_employee_id = $this->request->getPost('employee_id', FILTER_SANITIZE_NUMBER_INT);
|
||||
|
||||
if (!$this->employee->has_grant('employees', $current_employee_id)) {
|
||||
if ($expense_id == NEW_ENTRY) {
|
||||
$employee_id = $current_employee_id;
|
||||
} else {
|
||||
$existing_expense = $this->expense->get_info($expense_id);
|
||||
$employee_id = $existing_expense->employee_id;
|
||||
}
|
||||
} else {
|
||||
$employee_id = $submitted_employee_id;
|
||||
}
|
||||
|
||||
$expense_data = [
|
||||
'date' => $date_formatter->format('Y-m-d H:i:s'),
|
||||
'supplier_id' => $this->request->getPost('supplier_id') == '' ? null : $this->request->getPost('supplier_id', FILTER_SANITIZE_NUMBER_INT),
|
||||
@@ -161,7 +183,7 @@ class Expenses extends Secure_Controller
|
||||
'payment_type' => $this->request->getPost('payment_type', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
|
||||
'expense_category_id' => $this->request->getPost('expense_category_id', FILTER_SANITIZE_NUMBER_INT),
|
||||
'description' => $this->request->getPost('description', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
|
||||
'employee_id' => $this->request->getPost('employee_id', FILTER_SANITIZE_NUMBER_INT),
|
||||
'employee_id' => $employee_id,
|
||||
'deleted' => $this->request->getPost('deleted') != null
|
||||
];
|
||||
|
||||
|
||||
@@ -36,19 +36,18 @@ class Home extends Secure_Controller
|
||||
/**
|
||||
* Load "change employee password" form
|
||||
*
|
||||
* @return string
|
||||
* @return ResponseInterface|string
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function getChangePassword(int $employeeId = NEW_ENTRY): string
|
||||
public function getChangePassword(int $employeeId = NEW_ENTRY)
|
||||
{
|
||||
$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();
|
||||
if (!$this->employee->isAdmin($currentPersonId) && $employeeId !== $currentPersonId) {
|
||||
return $this->response->setStatusCode(403)->setBody(lang('Employees.unauthorized_modify'));
|
||||
}
|
||||
|
||||
$person_info = $this->employee->get_info($employeeId);
|
||||
@@ -71,7 +70,7 @@ class Home extends Secure_Controller
|
||||
|
||||
$employeeId = $employeeId === NEW_ENTRY ? $currentUser->person_id : $employeeId;
|
||||
|
||||
if (!$this->employee->can_modify_employee($employeeId, $currentUser->person_id)) {
|
||||
if (!$this->employee->isAdmin($currentUser->person_id) && $employeeId !== $currentUser->person_id) {
|
||||
return $this->response->setStatusCode(403)->setJSON([
|
||||
'success' => false,
|
||||
'message' => lang('Employees.unauthorized_modify')
|
||||
|
||||
@@ -73,7 +73,12 @@ class Items extends Secure_Controller
|
||||
$this->session->set('allow_temp_items', 0);
|
||||
|
||||
$data['table_headers'] = get_items_manage_table_headers();
|
||||
$data['stock_location'] = $this->item_lib->get_item_location();
|
||||
|
||||
// Restore stock_location from URL or session
|
||||
$stockLocation = $this->request->getGet('stock_location', FILTER_SANITIZE_NUMBER_INT);
|
||||
$data['stock_location'] = $stockLocation
|
||||
? $stockLocation
|
||||
: $this->item_lib->get_item_location();
|
||||
$data['stock_locations'] = $this->stock_location->get_allowed_locations();
|
||||
|
||||
// Filters that will be loaded in the multiselect dropdown
|
||||
@@ -87,6 +92,9 @@ class Items extends Secure_Controller
|
||||
'temporary' => lang('Items.temp')
|
||||
];
|
||||
|
||||
// Restore filters from URL
|
||||
$data = array_merge($data, restoreTableFilters($this->request));
|
||||
|
||||
return view('items/manage', $data);
|
||||
}
|
||||
|
||||
|
||||
71
app/Controllers/Payments/Webhook.php
Normal file
71
app/Controllers/Payments/Webhook.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers\Payments;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Libraries\Payments\PaymentProviderRegistry;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
|
||||
class Webhook extends BaseController
|
||||
{
|
||||
public function handle(string $providerId): ResponseInterface
|
||||
{
|
||||
$provider = PaymentProviderRegistry::getInstance()->getProvider($providerId);
|
||||
|
||||
if ($provider === null) {
|
||||
log_message('error', "Webhook received for unknown provider: {$providerId}");
|
||||
return $this->response->setStatusCode(404)->setJSON([
|
||||
'success' => false,
|
||||
'error' => 'Provider not found'
|
||||
]);
|
||||
}
|
||||
|
||||
$rawInput = $this->request->getBody();
|
||||
$data = json_decode($rawInput, true) ?? [];
|
||||
|
||||
if (empty($rawInput)) {
|
||||
$data = $this->request->getPost();
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $provider->processCallback($data);
|
||||
|
||||
if ($result['success'] ?? false) {
|
||||
log_message('info', "Webhook processed successfully for provider: {$providerId}", $result);
|
||||
return $this->response->setStatusCode(200)->setJSON($result);
|
||||
}
|
||||
|
||||
log_message('warning', "Webhook processing failed for provider: {$providerId}", $result);
|
||||
return $this->response->setStatusCode(400)->setJSON($result);
|
||||
} catch (\Exception $e) {
|
||||
log_message('error', "Webhook exception for provider {$providerId}: " . $e->getMessage());
|
||||
return $this->response->setStatusCode(500)->setJSON([
|
||||
'success' => false,
|
||||
'error' => 'Internal server error'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function status(string $providerId, string $transactionId): ResponseInterface
|
||||
{
|
||||
$provider = PaymentProviderRegistry::getInstance()->getProvider($providerId);
|
||||
|
||||
if ($provider === null) {
|
||||
return $this->response->setStatusCode(404)->setJSON([
|
||||
'success' => false,
|
||||
'error' => 'Provider not found'
|
||||
]);
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $provider->getPaymentStatus($transactionId);
|
||||
return $this->response->setStatusCode(200)->setJSON($result);
|
||||
} catch (\Exception $e) {
|
||||
log_message('error', "Status check exception for provider {$providerId}: " . $e->getMessage());
|
||||
return $this->response->setStatusCode(500)->setJSON([
|
||||
'success' => false,
|
||||
'error' => 'Internal server error'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,15 +241,26 @@ class Receivings extends Secure_Controller
|
||||
$data['suppliers'][$supplier->person_id] = $supplier->first_name . ' ' . $supplier->last_name;
|
||||
}
|
||||
|
||||
$receiving_info = $this->receiving->get_info($receiving_id)->getRowArray();
|
||||
|
||||
$current_employee_id = $this->employee->get_logged_in_employee_info()->person_id;
|
||||
$can_assign_employee = $this->employee->has_grant('employees', $current_employee_id);
|
||||
|
||||
$data['employees'] = [];
|
||||
foreach ($this->employee->get_all()->getResult() as $employee) {
|
||||
$data['employees'][$employee->person_id] = $employee->first_name . ' ' . $employee->last_name;
|
||||
if ($can_assign_employee) {
|
||||
foreach ($this->employee->get_all()->getResult() as $employee) {
|
||||
$data['employees'][$employee->person_id] = $employee->first_name . ' ' . $employee->last_name;
|
||||
}
|
||||
} else {
|
||||
$stored_employee_id = $receiving_info['employee_id'];
|
||||
$stored_employee = $this->employee->get_info($stored_employee_id);
|
||||
$data['employees'][$stored_employee_id] = $stored_employee->first_name . ' ' . $stored_employee->last_name;
|
||||
}
|
||||
|
||||
$receiving_info = $this->receiving->get_info($receiving_id)->getRowArray();
|
||||
$data['selected_supplier_name'] = !empty($receiving_info['supplier_id']) ? $receiving_info['company_name'] : '';
|
||||
$data['selected_supplier_id'] = $receiving_info['supplier_id'];
|
||||
$data['receiving_info'] = $receiving_info;
|
||||
$data['can_assign_employee'] = $can_assign_employee;
|
||||
|
||||
return view('receivings/form', $data);
|
||||
}
|
||||
@@ -491,10 +502,20 @@ class Receivings extends Secure_Controller
|
||||
$date_formatter = date_create_from_format($this->config['dateformat'] . ' ' . $this->config['timeformat'], $newdate);
|
||||
$receiving_time = $date_formatter->format('Y-m-d H:i:s');
|
||||
|
||||
$current_employee_id = $this->employee->get_logged_in_employee_info()->person_id;
|
||||
$submitted_employee_id = $this->request->getPost('employee_id', FILTER_SANITIZE_NUMBER_INT);
|
||||
|
||||
if (!$this->employee->has_grant('employees', $current_employee_id)) {
|
||||
$existing_receiving = $this->receiving->get_info($receiving_id)->getRowArray();
|
||||
$employee_id = $existing_receiving['employee_id'];
|
||||
} else {
|
||||
$employee_id = $submitted_employee_id;
|
||||
}
|
||||
|
||||
$receiving_data = [
|
||||
'receiving_time' => $receiving_time,
|
||||
'supplier_id' => $this->request->getPost('supplier_id') ? $this->request->getPost('supplier_id', FILTER_SANITIZE_NUMBER_INT) : null,
|
||||
'employee_id' => $this->request->getPost('employee_id', FILTER_SANITIZE_NUMBER_INT),
|
||||
'employee_id' => $employee_id,
|
||||
'comment' => $this->request->getPost('comment', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
|
||||
'reference' => $this->request->getPost('reference') != '' ? $this->request->getPost('reference', FILTER_SANITIZE_FULL_SPECIAL_CHARS) : null
|
||||
];
|
||||
|
||||
@@ -1776,7 +1776,7 @@ class Reports extends Secure_Controller
|
||||
{
|
||||
$this->clearCache();
|
||||
|
||||
$definition_names = $this->attribute->get_definitions_by_flags(attribute::SHOW_IN_SALES);
|
||||
$definition_names = $this->attribute->get_definitions_by_flags(attribute::SHOW_IN_SALES, true);
|
||||
|
||||
$inputs = [
|
||||
'start_date' => $start_date,
|
||||
@@ -1789,7 +1789,12 @@ class Reports extends Secure_Controller
|
||||
$this->detailed_sales->create($inputs);
|
||||
|
||||
$columns = $this->detailed_sales->getDataColumns();
|
||||
$columns['details'] = array_merge($columns['details'], $definition_names);
|
||||
// Extract just names for column headers
|
||||
$definitionHeaders = [];
|
||||
foreach ($definition_names as $definition_id => $definitionInfo) {
|
||||
$definitionHeaders[$definition_id] = $definitionInfo['name'];
|
||||
}
|
||||
$columns['details'] = array_merge($columns['details'], $definitionHeaders);
|
||||
|
||||
$headers = $columns;
|
||||
|
||||
@@ -1930,14 +1935,19 @@ class Reports extends Secure_Controller
|
||||
{
|
||||
$this->clearCache();
|
||||
|
||||
$definition_names = $this->attribute->get_definitions_by_flags(attribute::SHOW_IN_RECEIVINGS);
|
||||
$definition_names = $this->attribute->get_definitions_by_flags(attribute::SHOW_IN_RECEIVINGS, true);
|
||||
|
||||
$inputs = ['start_date' => $start_date, 'end_date' => $end_date, 'receiving_type' => $receiving_type, 'location_id' => $location_id, 'definition_ids' => array_keys($definition_names)];
|
||||
|
||||
$this->detailed_receivings->create($inputs);
|
||||
|
||||
$columns = $this->detailed_receivings->getDataColumns();
|
||||
$columns['details'] = array_merge($columns['details'], $definition_names);
|
||||
// Extract just names for column headers
|
||||
$definitionHeaders = [];
|
||||
foreach ($definition_names as $definition_id => $definitionInfo) {
|
||||
$definitionHeaders[$definition_id] = $definitionInfo['name'];
|
||||
}
|
||||
$columns['details'] = array_merge($columns['details'], $definitionHeaders);
|
||||
|
||||
$headers = $columns;
|
||||
$report_data = $this->detailed_receivings->getData($inputs);
|
||||
|
||||
@@ -20,6 +20,7 @@ use App\Models\Stock_location;
|
||||
use App\Models\Tokens\Token_invoice_count;
|
||||
use App\Models\Tokens\Token_customer;
|
||||
use App\Models\Tokens\Token_invoice_sequence;
|
||||
use CodeIgniter\Events\Events;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\Services;
|
||||
use Config\OSPOS;
|
||||
@@ -75,15 +76,15 @@ class Sales extends Secure_Controller
|
||||
/**
|
||||
* Load the sale edit modal. Used in app/Views/sales/register.php.
|
||||
*
|
||||
* @return string
|
||||
* @return ResponseInterface|string
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function getManage(): string
|
||||
public function getManage(): ResponseInterface|string
|
||||
{
|
||||
$person_id = $this->session->get('person_id');
|
||||
$personId = $this->session->get('person_id');
|
||||
|
||||
if (!$this->employee->has_grant('reports_sales', $person_id)) {
|
||||
redirect('no_access/sales/reports_sales');
|
||||
if (!$this->employee->has_grant('reports_sales', $personId)) {
|
||||
return redirect()->to('no_access/sales/reports_sales');
|
||||
} else {
|
||||
$data['table_headers'] = get_sales_manage_table_headers();
|
||||
|
||||
@@ -92,18 +93,31 @@ class Sales extends Secure_Controller
|
||||
'only_due' => lang('Sales.due_filter'),
|
||||
'only_check' => lang('Sales.check_filter'),
|
||||
'only_creditcard' => lang('Sales.credit_filter'),
|
||||
'only_debit' => lang('Sales.debit'),
|
||||
'only_invoices' => lang('Sales.invoice_filter'),
|
||||
'selected_customer' => lang('Sales.selected_customer')
|
||||
];
|
||||
|
||||
if ($this->sale_lib->get_customer() != -1) {
|
||||
$selected_filters = ['selected_customer'];
|
||||
$selectedFilters = ['selected_customer'];
|
||||
$data['customer_selected'] = true;
|
||||
} else {
|
||||
$data['customer_selected'] = false;
|
||||
$selected_filters = [];
|
||||
$selectedFilters = [];
|
||||
}
|
||||
$data['selected_filters'] = $selected_filters;
|
||||
|
||||
// Restore filters from URL query string
|
||||
$filters = restoreTableFilters($this->request);
|
||||
if (!empty($filters['selected_filters'])) {
|
||||
$selectedFilters = array_merge($selectedFilters, $filters['selected_filters']);
|
||||
}
|
||||
if (isset($filters['start_date'])) {
|
||||
$data['start_date'] = $filters['start_date'];
|
||||
}
|
||||
if (isset($filters['end_date'])) {
|
||||
$data['end_date'] = $filters['end_date'];
|
||||
}
|
||||
$data['selected_filters'] = $selectedFilters;
|
||||
|
||||
return view('sales/manage', $data);
|
||||
}
|
||||
@@ -142,6 +156,7 @@ class Sales extends Secure_Controller
|
||||
'only_check' => false,
|
||||
'selected_customer' => false,
|
||||
'only_creditcard' => false,
|
||||
'only_debit' => false,
|
||||
'only_invoices' => $this->config['invoice_enable'] && $this->request->getGet('only_invoices', FILTER_SANITIZE_NUMBER_INT),
|
||||
'is_valid_receipt' => $this->sale->is_valid_receipt($search)
|
||||
];
|
||||
@@ -457,6 +472,13 @@ class Sales extends Secure_Controller
|
||||
}
|
||||
}
|
||||
|
||||
Events::trigger('payment_initiated', [
|
||||
'payment_type' => $payment_type,
|
||||
'amount' => $amount_tendered ?? 0,
|
||||
'sale_id' => $this->sale_lib->get_sale_id(),
|
||||
'customer_id' => $this->sale_lib->get_customer(),
|
||||
]);
|
||||
|
||||
return $this->_reload($data);
|
||||
}
|
||||
|
||||
@@ -772,8 +794,18 @@ class Sales extends Secure_Controller
|
||||
$data['error_message'] = lang('Sales.transaction_failed');
|
||||
} else {
|
||||
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']);
|
||||
return view('sales/' . $invoice_view, $data);
|
||||
|
||||
Events::trigger('sale_completed', [
|
||||
'sale_id' => $data['sale_id_num'],
|
||||
'customer_id' => $customer_id,
|
||||
'employee_id' => $employee_id,
|
||||
'total' => $data['total'],
|
||||
'payments' => $data['payments'],
|
||||
'sale_type' => $sale_type,
|
||||
]);
|
||||
|
||||
$this->sale_lib->clear_all();
|
||||
return view('sales/' . $invoice_view, $data);
|
||||
}
|
||||
}
|
||||
} elseif ($this->sale_lib->is_work_order_mode()) {
|
||||
@@ -806,9 +838,8 @@ class Sales extends Secure_Controller
|
||||
|
||||
$data['barcode'] = null;
|
||||
|
||||
return view('sales/work_order', $data);
|
||||
$this->sale_lib->clear_mode();
|
||||
$this->sale_lib->clear_all();
|
||||
return view('sales/work_order', $data);
|
||||
}
|
||||
} elseif ($this->sale_lib->is_quote_mode()) {
|
||||
$data['sales_quote'] = lang('Sales.quote');
|
||||
@@ -834,9 +865,8 @@ class Sales extends Secure_Controller
|
||||
$data['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']);
|
||||
$data['barcode'] = null;
|
||||
|
||||
return view('sales/quote', $data);
|
||||
$this->sale_lib->clear_mode();
|
||||
$this->sale_lib->clear_all();
|
||||
return view('sales/quote', $data);
|
||||
}
|
||||
} else {
|
||||
// Save the data to the sales table
|
||||
@@ -857,8 +887,18 @@ class Sales extends Secure_Controller
|
||||
$data['error_message'] = lang('Sales.transaction_failed');
|
||||
} else {
|
||||
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']);
|
||||
return view('sales/receipt', $data);
|
||||
|
||||
Events::trigger('sale_completed', [
|
||||
'sale_id' => $data['sale_id_num'],
|
||||
'customer_id' => $customer_id,
|
||||
'employee_id' => $employee_id,
|
||||
'total' => $data['total'],
|
||||
'payments' => $data['payments'],
|
||||
'sale_type' => $sale_type,
|
||||
]);
|
||||
|
||||
$this->sale_lib->clear_all();
|
||||
return view('sales/receipt', $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
60
app/Database/Migrations/20170501000000_initial_schema.php
Normal file
60
app/Database/Migrations/20170501000000_initial_schema.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class Migration_Initial_Schema extends Migration
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a migration step.
|
||||
* Only runs on fresh installs - skips if database already has tables.
|
||||
*
|
||||
* For testing: CI4's DatabaseTestTrait with $refresh=true handles table
|
||||
* cleanup/creation automatically. This migration only loads initial schema
|
||||
* on fresh databases where no application tables exist.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// Check if core application tables exist (existing install)
|
||||
// Note: migrations table may exist even on fresh DB due to migration tracking
|
||||
$tables = $this->db->listTables();
|
||||
|
||||
// Check for a core application table, not just migrations table
|
||||
foreach ($tables as $table) {
|
||||
// Strip prefix if present for comparison
|
||||
$tableName = str_replace($this->db->getPrefix(), '', $table);
|
||||
if (in_array($tableName, ['app_config', 'items', 'employees', 'people'])) {
|
||||
// Database already populated - skip initial schema
|
||||
// This is an existing installation upgrading from older version
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Fresh install - load initial schema
|
||||
helper('migration');
|
||||
execute_script(APPPATH . 'Database/Migrations/sqlscripts/initial_schema.sql');
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert a migration step.
|
||||
* Cannot revert initial schema - would lose all data.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Cannot safely revert initial schema
|
||||
// Would require dropping all tables which would lose all data
|
||||
$this->db->query('SET FOREIGN_KEY_CHECKS = 0');
|
||||
|
||||
foreach ($this->db->listTables() as $table) {
|
||||
$this->db->query('DROP TABLE IF EXISTS `' . $table . '`');
|
||||
}
|
||||
|
||||
$this->db->query('SET FOREIGN_KEY_CHECKS = 1');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class Migration_PaymentTransactions extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$forge = \Config\Services::forge();
|
||||
|
||||
$forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true
|
||||
],
|
||||
'provider_id' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 100,
|
||||
'null' => false
|
||||
],
|
||||
'sale_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true
|
||||
],
|
||||
'transaction_id' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => false
|
||||
],
|
||||
'amount' => [
|
||||
'type' => 'DECIMAL',
|
||||
'constraint' => '15,2',
|
||||
'null' => false
|
||||
],
|
||||
'currency' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 3,
|
||||
'default' => 'USD',
|
||||
'null' => false
|
||||
],
|
||||
'status' => [
|
||||
'type' => 'ENUM',
|
||||
'constraint' => ['pending', 'authorized', 'completed', 'failed', 'refunded', 'cancelled'],
|
||||
'default' => 'pending',
|
||||
'null' => false
|
||||
],
|
||||
'metadata' => [
|
||||
'type' => 'JSON',
|
||||
'null' => true
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'null' => true
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'TIMESTAMP',
|
||||
'null' => true
|
||||
]
|
||||
]);
|
||||
|
||||
$forge->addKey('id', true);
|
||||
$forge->addKey('provider_id');
|
||||
$forge->addKey('sale_id');
|
||||
$forge->addKey('transaction_id');
|
||||
$forge->addKey('status');
|
||||
|
||||
$forge->createTable('payment_transactions', true);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$forge = \Config\Services::forge();
|
||||
$forge->dropTable('payment_transactions', true);
|
||||
}
|
||||
}
|
||||
@@ -730,3 +730,148 @@ CREATE TABLE `ospos_suppliers` (
|
||||
--
|
||||
-- Dumping data for table `ospos_suppliers`
|
||||
--
|
||||
--
|
||||
-- Constraints for dumped tables
|
||||
--
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_customers`
|
||||
--
|
||||
ALTER TABLE `ospos_customers`
|
||||
ADD CONSTRAINT `ospos_customers_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_employees`
|
||||
--
|
||||
ALTER TABLE `ospos_employees`
|
||||
ADD CONSTRAINT `ospos_employees_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_inventory`
|
||||
--
|
||||
ALTER TABLE `ospos_inventory`
|
||||
ADD CONSTRAINT `ospos_inventory_ibfk_1` FOREIGN KEY (`trans_items`) REFERENCES `ospos_items` (`item_id`),
|
||||
ADD CONSTRAINT `ospos_inventory_ibfk_2` FOREIGN KEY (`trans_user`) REFERENCES `ospos_employees` (`person_id`),
|
||||
ADD CONSTRAINT `ospos_inventory_ibfk_3` FOREIGN KEY (`trans_location`) REFERENCES `ospos_stock_locations` (`location_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_items`
|
||||
--
|
||||
ALTER TABLE `ospos_items`
|
||||
ADD CONSTRAINT `ospos_items_ibfk_1` FOREIGN KEY (`supplier_id`) REFERENCES `ospos_suppliers` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_items_taxes`
|
||||
--
|
||||
ALTER TABLE `ospos_items_taxes`
|
||||
ADD CONSTRAINT `ospos_items_taxes_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`) ON DELETE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_item_kit_items`
|
||||
--
|
||||
ALTER TABLE `ospos_item_kit_items`
|
||||
ADD CONSTRAINT `ospos_item_kit_items_ibfk_1` FOREIGN KEY (`item_kit_id`) REFERENCES `ospos_item_kits` (`item_kit_id`) ON DELETE CASCADE,
|
||||
ADD CONSTRAINT `ospos_item_kit_items_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`) ON DELETE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_permissions`
|
||||
--
|
||||
ALTER TABLE `ospos_permissions`
|
||||
ADD CONSTRAINT `ospos_permissions_ibfk_1` FOREIGN KEY (`module_id`) REFERENCES `ospos_modules` (`module_id`) ON DELETE CASCADE,
|
||||
ADD CONSTRAINT `ospos_permissions_ibfk_2` FOREIGN KEY (`location_id`) REFERENCES `ospos_stock_locations` (`location_id`) ON DELETE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_grants`
|
||||
--
|
||||
ALTER TABLE `ospos_grants`
|
||||
ADD CONSTRAINT `ospos_grants_ibfk_1` foreign key (`permission_id`) references `ospos_permissions` (`permission_id`) ON DELETE CASCADE,
|
||||
ADD CONSTRAINT `ospos_grants_ibfk_2` foreign key (`person_id`) references `ospos_employees` (`person_id`) ON DELETE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_receivings`
|
||||
--
|
||||
ALTER TABLE `ospos_receivings`
|
||||
ADD CONSTRAINT `ospos_receivings_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`),
|
||||
ADD CONSTRAINT `ospos_receivings_ibfk_2` FOREIGN KEY (`supplier_id`) REFERENCES `ospos_suppliers` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_receivings_items`
|
||||
--
|
||||
ALTER TABLE `ospos_receivings_items`
|
||||
ADD CONSTRAINT `ospos_receivings_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
|
||||
ADD CONSTRAINT `ospos_receivings_items_ibfk_2` FOREIGN KEY (`receiving_id`) REFERENCES `ospos_receivings` (`receiving_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales`
|
||||
--
|
||||
ALTER TABLE `ospos_sales`
|
||||
ADD CONSTRAINT `ospos_sales_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`),
|
||||
ADD CONSTRAINT `ospos_sales_ibfk_2` FOREIGN KEY (`customer_id`) REFERENCES `ospos_customers` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_items`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_items`
|
||||
ADD CONSTRAINT `ospos_sales_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
|
||||
ADD CONSTRAINT `ospos_sales_items_ibfk_2` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`),
|
||||
ADD CONSTRAINT `ospos_sales_items_ibfk_3` FOREIGN KEY (`item_location`) REFERENCES `ospos_stock_locations` (`location_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_items_taxes`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_items_taxes`
|
||||
ADD CONSTRAINT `ospos_sales_items_taxes_ibfk_1` FOREIGN KEY (`sale_id`,`item_id`,`line`) REFERENCES `ospos_sales_items` (`sale_id`,`item_id`,`line`),
|
||||
ADD CONSTRAINT `ospos_sales_items_taxes_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_payments`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_payments`
|
||||
ADD CONSTRAINT `ospos_sales_payments_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_suspended`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_suspended`
|
||||
ADD CONSTRAINT `ospos_sales_suspended_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`),
|
||||
ADD CONSTRAINT `ospos_sales_suspended_ibfk_2` FOREIGN KEY (`customer_id`) REFERENCES `ospos_customers` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_suspended_items`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_suspended_items`
|
||||
ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
|
||||
ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_2` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales_suspended` (`sale_id`),
|
||||
ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_3` FOREIGN KEY (`item_location`) REFERENCES `ospos_stock_locations` (`location_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_suspended_items_taxes`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_suspended_items_taxes`
|
||||
ADD CONSTRAINT `ospos_sales_suspended_items_taxes_ibfk_1` FOREIGN KEY (`sale_id`,`item_id`,`line`) REFERENCES `ospos_sales_suspended_items` (`sale_id`,`item_id`,`line`),
|
||||
ADD CONSTRAINT `ospos_sales_suspended_items_taxes_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_suspended_payments`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_suspended_payments`
|
||||
ADD CONSTRAINT `ospos_sales_suspended_payments_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales_suspended` (`sale_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_item_quantities`
|
||||
--
|
||||
ALTER TABLE `ospos_item_quantities`
|
||||
ADD CONSTRAINT `ospos_item_quantities_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
|
||||
ADD CONSTRAINT `ospos_item_quantities_ibfk_2` FOREIGN KEY (`location_id`) REFERENCES `ospos_stock_locations` (`location_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_suppliers`
|
||||
--
|
||||
ALTER TABLE `ospos_suppliers`
|
||||
ADD CONSTRAINT `ospos_suppliers_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_giftcards`
|
||||
--
|
||||
ALTER TABLE `ospos_giftcards`
|
||||
ADD CONSTRAINT `ospos_giftcards_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
|
||||
@@ -1,145 +0,0 @@
|
||||
--
|
||||
-- Constraints for dumped tables
|
||||
--
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_customers`
|
||||
--
|
||||
ALTER TABLE `ospos_customers`
|
||||
ADD CONSTRAINT `ospos_customers_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_employees`
|
||||
--
|
||||
ALTER TABLE `ospos_employees`
|
||||
ADD CONSTRAINT `ospos_employees_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_inventory`
|
||||
--
|
||||
ALTER TABLE `ospos_inventory`
|
||||
ADD CONSTRAINT `ospos_inventory_ibfk_1` FOREIGN KEY (`trans_items`) REFERENCES `ospos_items` (`item_id`),
|
||||
ADD CONSTRAINT `ospos_inventory_ibfk_2` FOREIGN KEY (`trans_user`) REFERENCES `ospos_employees` (`person_id`),
|
||||
ADD CONSTRAINT `ospos_inventory_ibfk_3` FOREIGN KEY (`trans_location`) REFERENCES `ospos_stock_locations` (`location_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_items`
|
||||
--
|
||||
ALTER TABLE `ospos_items`
|
||||
ADD CONSTRAINT `ospos_items_ibfk_1` FOREIGN KEY (`supplier_id`) REFERENCES `ospos_suppliers` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_items_taxes`
|
||||
--
|
||||
ALTER TABLE `ospos_items_taxes`
|
||||
ADD CONSTRAINT `ospos_items_taxes_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`) ON DELETE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_item_kit_items`
|
||||
--
|
||||
ALTER TABLE `ospos_item_kit_items`
|
||||
ADD CONSTRAINT `ospos_item_kit_items_ibfk_1` FOREIGN KEY (`item_kit_id`) REFERENCES `ospos_item_kits` (`item_kit_id`) ON DELETE CASCADE,
|
||||
ADD CONSTRAINT `ospos_item_kit_items_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`) ON DELETE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_permissions`
|
||||
--
|
||||
ALTER TABLE `ospos_permissions`
|
||||
ADD CONSTRAINT `ospos_permissions_ibfk_1` FOREIGN KEY (`module_id`) REFERENCES `ospos_modules` (`module_id`) ON DELETE CASCADE,
|
||||
ADD CONSTRAINT `ospos_permissions_ibfk_2` FOREIGN KEY (`location_id`) REFERENCES `ospos_stock_locations` (`location_id`) ON DELETE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_grants`
|
||||
--
|
||||
ALTER TABLE `ospos_grants`
|
||||
ADD CONSTRAINT `ospos_grants_ibfk_1` foreign key (`permission_id`) references `ospos_permissions` (`permission_id`) ON DELETE CASCADE,
|
||||
ADD CONSTRAINT `ospos_grants_ibfk_2` foreign key (`person_id`) references `ospos_employees` (`person_id`) ON DELETE CASCADE;
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_receivings`
|
||||
--
|
||||
ALTER TABLE `ospos_receivings`
|
||||
ADD CONSTRAINT `ospos_receivings_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`),
|
||||
ADD CONSTRAINT `ospos_receivings_ibfk_2` FOREIGN KEY (`supplier_id`) REFERENCES `ospos_suppliers` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_receivings_items`
|
||||
--
|
||||
ALTER TABLE `ospos_receivings_items`
|
||||
ADD CONSTRAINT `ospos_receivings_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
|
||||
ADD CONSTRAINT `ospos_receivings_items_ibfk_2` FOREIGN KEY (`receiving_id`) REFERENCES `ospos_receivings` (`receiving_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales`
|
||||
--
|
||||
ALTER TABLE `ospos_sales`
|
||||
ADD CONSTRAINT `ospos_sales_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`),
|
||||
ADD CONSTRAINT `ospos_sales_ibfk_2` FOREIGN KEY (`customer_id`) REFERENCES `ospos_customers` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_items`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_items`
|
||||
ADD CONSTRAINT `ospos_sales_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
|
||||
ADD CONSTRAINT `ospos_sales_items_ibfk_2` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`),
|
||||
ADD CONSTRAINT `ospos_sales_items_ibfk_3` FOREIGN KEY (`item_location`) REFERENCES `ospos_stock_locations` (`location_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_items_taxes`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_items_taxes`
|
||||
ADD CONSTRAINT `ospos_sales_items_taxes_ibfk_1` FOREIGN KEY (`sale_id`,`item_id`,`line`) REFERENCES `ospos_sales_items` (`sale_id`,`item_id`,`line`),
|
||||
ADD CONSTRAINT `ospos_sales_items_taxes_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_payments`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_payments`
|
||||
ADD CONSTRAINT `ospos_sales_payments_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_suspended`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_suspended`
|
||||
ADD CONSTRAINT `ospos_sales_suspended_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`),
|
||||
ADD CONSTRAINT `ospos_sales_suspended_ibfk_2` FOREIGN KEY (`customer_id`) REFERENCES `ospos_customers` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_suspended_items`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_suspended_items`
|
||||
ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
|
||||
ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_2` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales_suspended` (`sale_id`),
|
||||
ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_3` FOREIGN KEY (`item_location`) REFERENCES `ospos_stock_locations` (`location_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_suspended_items_taxes`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_suspended_items_taxes`
|
||||
ADD CONSTRAINT `ospos_sales_suspended_items_taxes_ibfk_1` FOREIGN KEY (`sale_id`,`item_id`,`line`) REFERENCES `ospos_sales_suspended_items` (`sale_id`,`item_id`,`line`),
|
||||
ADD CONSTRAINT `ospos_sales_suspended_items_taxes_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_sales_suspended_payments`
|
||||
--
|
||||
ALTER TABLE `ospos_sales_suspended_payments`
|
||||
ADD CONSTRAINT `ospos_sales_suspended_payments_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales_suspended` (`sale_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_item_quantities`
|
||||
--
|
||||
ALTER TABLE `ospos_item_quantities`
|
||||
ADD CONSTRAINT `ospos_item_quantities_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
|
||||
ADD CONSTRAINT `ospos_item_quantities_ibfk_2` FOREIGN KEY (`location_id`) REFERENCES `ospos_stock_locations` (`location_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_suppliers`
|
||||
--
|
||||
ALTER TABLE `ospos_suppliers`
|
||||
ADD CONSTRAINT `ospos_suppliers_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
|
||||
|
||||
--
|
||||
-- Constraints for table `ospos_giftcards`
|
||||
--
|
||||
ALTER TABLE `ospos_giftcards`
|
||||
ADD CONSTRAINT `ospos_giftcards_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
|
||||
58
app/Events/PaymentEvents.php
Normal file
58
app/Events/PaymentEvents.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Libraries\Payments\PaymentProviderRegistry;
|
||||
use CodeIgniter\Events\Events;
|
||||
use Config\Services;
|
||||
|
||||
class PaymentEvents
|
||||
{
|
||||
public static function initialize(): void
|
||||
{
|
||||
Events::on('payment_initiated', [static::class, 'onPaymentInitiated']);
|
||||
Events::on('payment_completed', [static::class, 'onPaymentCompleted']);
|
||||
Events::on('payment_failed', [static::class, 'onPaymentFailed']);
|
||||
Events::on('sale_completed', [static::class, 'onSaleCompleted']);
|
||||
}
|
||||
|
||||
public static function onPaymentInitiated(array $data): void
|
||||
{
|
||||
log_message('debug', sprintf(
|
||||
'Payment initiated: type=%s, amount=%s, sale_id=%s',
|
||||
$data['payment_type'] ?? 'unknown',
|
||||
$data['amount'] ?? 0,
|
||||
$data['sale_id'] ?? 'pending'
|
||||
));
|
||||
}
|
||||
|
||||
public static function onPaymentCompleted(array $data): void
|
||||
{
|
||||
log_message('debug', sprintf(
|
||||
'Payment completed: type=%s, amount=%s, sale_id=%s',
|
||||
$data['payment_type'] ?? 'unknown',
|
||||
$data['amount'] ?? 0,
|
||||
$data['sale_id'] ?? 'pending'
|
||||
));
|
||||
}
|
||||
|
||||
public static function onPaymentFailed(array $data): void
|
||||
{
|
||||
log_message('warning', sprintf(
|
||||
'Payment failed: type=%s, amount=%s, error=%s',
|
||||
$data['payment_type'] ?? 'unknown',
|
||||
$data['amount'] ?? 0,
|
||||
$data['error'] ?? 'unknown error'
|
||||
));
|
||||
}
|
||||
|
||||
public static function onSaleCompleted(array $data): void
|
||||
{
|
||||
log_message('info', sprintf(
|
||||
'Sale completed: sale_id=%s, total=%s, payments=%s',
|
||||
$data['sale_id'] ?? 'unknown',
|
||||
$data['total'] ?? 0,
|
||||
json_encode($data['payments'] ?? [])
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Employee;
|
||||
use CodeIgniter\Events\Events;
|
||||
use Config\OSPOS;
|
||||
|
||||
/**
|
||||
@@ -276,6 +277,12 @@ function get_payment_options(): array
|
||||
$payments[lang('Sales.upi')] = lang('Sales.upi');
|
||||
}
|
||||
|
||||
// Allow payment provider plugins to add additional payment options
|
||||
$eventPayments = Events::trigger('payment_options', $payments);
|
||||
if (is_array($eventPayments)) {
|
||||
return $eventPayments;
|
||||
}
|
||||
|
||||
return $payments;
|
||||
}
|
||||
|
||||
|
||||
64
app/Helpers/payment_helper.php
Normal file
64
app/Helpers/payment_helper.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
use App\Libraries\Payments\PaymentProviderRegistry;
|
||||
use CodeIgniter\Events\Events;
|
||||
|
||||
if (!function_exists('register_payment_provider')) {
|
||||
function register_payment_provider(App\Libraries\Payments\PaymentProviderInterface $provider): void
|
||||
{
|
||||
PaymentProviderRegistry::getInstance()->register($provider);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_payment_providers')) {
|
||||
function get_payment_providers(): array
|
||||
{
|
||||
return PaymentProviderRegistry::getInstance()->getProviders();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_enabled_payment_providers')) {
|
||||
function get_enabled_payment_providers(): array
|
||||
{
|
||||
return PaymentProviderRegistry::getInstance()->getEnabledProviders();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_enabled_payment_types')) {
|
||||
function get_enabled_payment_types(): array
|
||||
{
|
||||
return PaymentProviderRegistry::getInstance()->getEnabledPaymentTypes();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_payment_provider')) {
|
||||
function get_payment_provider(string $providerId): ?App\Libraries\Payments\PaymentProviderInterface
|
||||
{
|
||||
return PaymentProviderRegistry::getInstance()->getProvider($providerId);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('get_payment_provider_for_type')) {
|
||||
function get_payment_provider_for_type(string $paymentTypeKey): ?App\Libraries\Payments\PaymentProviderInterface
|
||||
{
|
||||
return PaymentProviderRegistry::getInstance()->getProviderForPaymentType($paymentTypeKey);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('payment_provider_content')) {
|
||||
function payment_provider_content(string $section, array $data = []): string
|
||||
{
|
||||
$results = Events::trigger("payment_view:{$section}", $data);
|
||||
$output = '';
|
||||
if (is_array($results)) {
|
||||
foreach ($results as $result) {
|
||||
if (is_string($result)) {
|
||||
$output .= $result;
|
||||
}
|
||||
}
|
||||
} elseif (is_string($results)) {
|
||||
$output = $results;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
@@ -408,7 +408,7 @@ function get_items_manage_table_headers(): string
|
||||
{
|
||||
$attribute = model(Attribute::class);
|
||||
$config = config(OSPOS::class)->settings;
|
||||
$definition_names = $attribute->get_definitions_by_flags($attribute::SHOW_IN_ITEMS); // TODO: this should be made into a constant in constants.php
|
||||
$definitionsWithTypes = $attribute->get_definitions_by_flags($attribute::SHOW_IN_ITEMS, true);
|
||||
|
||||
$headers = item_headers();
|
||||
|
||||
@@ -420,8 +420,8 @@ function get_items_manage_table_headers(): string
|
||||
|
||||
$headers[] = ['item_pic' => lang('Items.image'), 'sortable' => false];
|
||||
|
||||
foreach ($definition_names as $definition_id => $definition_name) {
|
||||
$headers[] = [$definition_id => $definition_name, 'sortable' => false];
|
||||
foreach ($definitionsWithTypes as $definition_id => $definitionInfo) {
|
||||
$headers[] = [$definition_id => $definitionInfo['name'], 'sortable' => false];
|
||||
}
|
||||
|
||||
$headers[] = ['inventory' => '', 'escape' => false];
|
||||
@@ -479,7 +479,7 @@ function get_item_data_row(object $item): array
|
||||
$item->name .= NAME_SEPARATOR . $item->pack_name;
|
||||
}
|
||||
|
||||
$definition_names = $attribute->get_definitions_by_flags($attribute::SHOW_IN_ITEMS);
|
||||
$definition_names = $attribute->get_definitions_by_flags($attribute::SHOW_IN_ITEMS, true);
|
||||
|
||||
$columns = [
|
||||
'items.item_id' => $item->item_id,
|
||||
@@ -634,7 +634,7 @@ function parse_attribute_values(array $columns, array $row): array
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $definition_names
|
||||
* @param array $definition_names Array of definition_id => ['name' => name, 'type' => type] or definition_id => name
|
||||
* @param array $row
|
||||
* @return array
|
||||
*/
|
||||
@@ -651,10 +651,16 @@ function expand_attribute_values(array $definition_names, array $row): array
|
||||
}
|
||||
|
||||
$attribute_values = [];
|
||||
foreach ($definition_names as $definition_id => $definition_name) {
|
||||
foreach ($definition_names as $definition_id => $definitionInfo) {
|
||||
if (isset($indexed_values[$definition_id])) {
|
||||
$attribute_value = $indexed_values[$definition_id];
|
||||
$attribute_values["$definition_id"] = $attribute_value;
|
||||
$raw_value = $indexed_values[$definition_id];
|
||||
|
||||
// Format DECIMAL attributes according to locale
|
||||
if (is_array($definitionInfo) && isset($definitionInfo['type']) && $definitionInfo['type'] === DECIMAL) {
|
||||
$attribute_values["$definition_id"] = to_decimals($raw_value);
|
||||
} else {
|
||||
$attribute_values["$definition_id"] = $raw_value;
|
||||
}
|
||||
} else {
|
||||
$attribute_values["$definition_id"] = "";
|
||||
}
|
||||
@@ -925,3 +931,24 @@ function get_controller(): string
|
||||
$controller_name_parts = explode('\\', $controller_name);
|
||||
return end($controller_name_parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores filter values from URL query string.
|
||||
*
|
||||
* @param CodeIgniter\HTTP\IncomingRequest $request The request object
|
||||
* @return array Array with 'start_date', 'end_date', and 'selected_filters' keys
|
||||
*/
|
||||
function restoreTableFilters($request): array
|
||||
{
|
||||
$startDate = $request->getGet('start_date', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$endDate = $request->getGet('end_date', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$urlFilters = $request->getGet('filters', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
|
||||
return array_filter([
|
||||
'start_date' => $startDate ?: null,
|
||||
'end_date' => $endDate ?: null,
|
||||
'selected_filters' => $urlFilters ?? []
|
||||
], function($value) {
|
||||
return $value !== null && $value !== [];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "هل أنت متأكد من أنك تريد حذف الميزات المحددة ؟",
|
||||
"confirm_restore" => "هل أنت متأكد من أنك تريد استعادة السمة (السمات) المحددة؟",
|
||||
"definition_cannot_be_deleted" => "لا يمكن حذف السمات المحددة",
|
||||
"definition_invalid_group" => "المجموعة المحددة غير موجودة أو غير صالحة.",
|
||||
"definition_error_adding_updating" => "لا يمكن إضافة السمة {0} أو تحديثها. يرجى التحقق من سجل الخطأ.",
|
||||
"definition_flags" => "رؤية الميزات",
|
||||
"definition_group" => "المجموعة",
|
||||
|
||||
49
app/Language/ar-EG/Calendar.php
Normal file
49
app/Language/ar-EG/Calendar.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"su" => "أحد",
|
||||
"mo" => "اثنين",
|
||||
"tu" => "ثلاثاء",
|
||||
"we" => "أربعاء",
|
||||
"th" => "خميس",
|
||||
"fr" => "جمعة",
|
||||
"sa" => "سبت",
|
||||
"sun" => "الأحد",
|
||||
"mon" => "الاثنين",
|
||||
"tue" => "الثلاثاء",
|
||||
"wed" => "الأربعاء",
|
||||
"thu" => "الخميس",
|
||||
"fri" => "الجمعة",
|
||||
"sat" => "السبت",
|
||||
"sunday" => "الأحد",
|
||||
"monday" => "الاثنين",
|
||||
"tuesday" => "الثلاثاء",
|
||||
"wednesday" => "الأربعاء",
|
||||
"thursday" => "الخميس",
|
||||
"friday" => "الجمعة",
|
||||
"saturday" => "السبت",
|
||||
"jan" => "يناير",
|
||||
"feb" => "فبراير",
|
||||
"mar" => "مارس",
|
||||
"apr" => "أبريل",
|
||||
"may" => "مايو",
|
||||
"jun" => "يونيو",
|
||||
"jul" => "يوليو",
|
||||
"aug" => "أغسطس",
|
||||
"sep" => "سبتمبر",
|
||||
"oct" => "أكتوبر",
|
||||
"nov" => "نوفمبر",
|
||||
"dec" => "ديسمبر",
|
||||
"january" => "يناير",
|
||||
"february" => "فبراير",
|
||||
"march" => "مارس",
|
||||
"april" => "أبريل",
|
||||
"mayl" => "مايو",
|
||||
"june" => "يونيو",
|
||||
"july" => "يوليو",
|
||||
"august" => "أغسطس",
|
||||
"september" => "سبتمبر",
|
||||
"october" => "أكتوبر",
|
||||
"november" => "نوفمبر",
|
||||
"december" => "ديسمبر",
|
||||
];
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "هل أنت متأكد من أنك تريد حذف الميزات المحددة ؟",
|
||||
"confirm_restore" => "هل أنت متأكد من أنك تريد استعادة السمة (السمات) المحددة؟",
|
||||
"definition_cannot_be_deleted" => "لا يمكن حذف السمات المحددة",
|
||||
"definition_invalid_group" => "المجموعة المحددة غير موجودة أو غير صالحة.",
|
||||
"definition_error_adding_updating" => "لا يمكن إضافة السمة {0} أو تحديثها. يرجى التحقق من سجل الخطأ.",
|
||||
"definition_flags" => "رؤية الميزات",
|
||||
"definition_group" => "المجموعة",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Seçilmiş Atributları silmək istədiyinizdən əminsinizmi?",
|
||||
"confirm_restore" => "Seçilmiş atributları bərpa etmək istədiyinizə əminsinizmi?",
|
||||
"definition_cannot_be_deleted" => "Seçilmiş xüsusiyyətləri silmək olmadı",
|
||||
"definition_invalid_group" => "",
|
||||
"definition_error_adding_updating" => "{0} -in atributları əlavə oluna və yenilənə bilmədi. Lütfən XƏTA loq faylını yoxlayın.",
|
||||
"definition_flags" => "Atribut görünüşü",
|
||||
"definition_group" => "Qrup",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "",
|
||||
"confirm_restore" => "",
|
||||
"definition_cannot_be_deleted" => "",
|
||||
"definition_invalid_group" => "",
|
||||
"definition_error_adding_updating" => "",
|
||||
"definition_flags" => "",
|
||||
"definition_group" => "",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Da li ste sigurni da želite da izbrišete izabrani atribut?",
|
||||
"confirm_restore" => "Da li ste sigurni da želite vratiti izabrane atribute?",
|
||||
"definition_cannot_be_deleted" => "Nije moguće izbrisati izabrane atribut",
|
||||
"definition_invalid_group" => "",
|
||||
"definition_error_adding_updating" => "Atribut {0} nije moguće dodati ili ažurirati. Molimo provjerite dnevnik grešaka.",
|
||||
"definition_flags" => "Vidljivost atributa",
|
||||
"definition_group" => "Grupa",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "ئایا دڵنیای کە دەتەوێت تایبەتمەندییە هەڵبژێردراوەکە(کان) بسڕیتەوە؟",
|
||||
"confirm_restore" => "ئایا دڵنیای کە دەتەوێت تایبەتمەندییە هەڵبژێردراوەکە(کان) بگەڕێنیتەوە؟",
|
||||
"definition_cannot_be_deleted" => "نەتوانرا تایبەتمەندی هەڵبژێردراو بسڕدرێتەوە",
|
||||
"definition_invalid_group" => "",
|
||||
"definition_error_adding_updating" => "تایبەتمەندی {0} نەتوانرا زیاد بکرێت یان نوێ بکرێتەوە. تکایە لیستی هەڵەکان بپشکنە.",
|
||||
"definition_flags" => "توانای بینراویی تایبەتمەندی",
|
||||
"definition_group" => "گروپ",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "",
|
||||
"confirm_restore" => "",
|
||||
"definition_cannot_be_deleted" => "",
|
||||
"definition_invalid_group" => "",
|
||||
"definition_error_adding_updating" => "",
|
||||
"definition_flags" => "",
|
||||
"definition_group" => "",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Er du sikker på, at du vil slette de valgte egenskaber?",
|
||||
"confirm_restore" => "Er du sikker på, at du vil gendanne de valgte egenskaber?",
|
||||
"definition_cannot_be_deleted" => "De valgte egenskaber kunne ikke slettes",
|
||||
"definition_invalid_group" => "Den valgte gruppe findes ikke eller er ugyldig.",
|
||||
"definition_error_adding_updating" => "Egenskab {0} Kunne ikke tilføjes eller opdateres. Tjek venligst fejlprotokollen.",
|
||||
"definition_flags" => "Egenskabens Synlighed",
|
||||
"definition_group" => "Gruppe",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "",
|
||||
"confirm_restore" => "",
|
||||
"definition_cannot_be_deleted" => "",
|
||||
"definition_invalid_group" => "Die ausgewählte Gruppe existiert nicht oder ist ungültig.",
|
||||
"definition_error_adding_updating" => "",
|
||||
"definition_flags" => "",
|
||||
"definition_group" => "",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Sind Sie sicher, dass Sie die ausgewählten Attribute löschen möchten?",
|
||||
"confirm_restore" => "Sind Sie sicher, dass Sie die ausgewählten Attribute wiederherstellen möchten?",
|
||||
"definition_cannot_be_deleted" => "Ausgewählte Attribute konnten nicht gelöscht werden",
|
||||
"definition_invalid_group" => "Die ausgewählte Gruppe existiert nicht oder ist ungültig.",
|
||||
"definition_error_adding_updating" => "Das Attribut {0} konnte nicht hinzugefügt oder aktualisiert werden. Bitte überprüfen Sie den Error-Log.",
|
||||
"definition_flags" => "Attribut Sichtbarkeit",
|
||||
"definition_group" => "Gruppe",
|
||||
|
||||
49
app/Language/de-DE/Calendar.php
Normal file
49
app/Language/de-DE/Calendar.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"su" => "So",
|
||||
"mo" => "Mo",
|
||||
"tu" => "Di",
|
||||
"we" => "Mi",
|
||||
"th" => "Do",
|
||||
"fr" => "Fr",
|
||||
"sa" => "Sa",
|
||||
"sun" => "Son",
|
||||
"mon" => "Mon",
|
||||
"tue" => "Die",
|
||||
"wed" => "Mit",
|
||||
"thu" => "Don",
|
||||
"fri" => "Fre",
|
||||
"sat" => "Sam",
|
||||
"sunday" => "Sonntag",
|
||||
"monday" => "Montag",
|
||||
"tuesday" => "Dienstag",
|
||||
"wednesday" => "Mittwoch",
|
||||
"thursday" => "Donnerstag",
|
||||
"friday" => "Freitag",
|
||||
"saturday" => "Samstag",
|
||||
"jan" => "Jan",
|
||||
"feb" => "Feb",
|
||||
"mar" => "Mär",
|
||||
"apr" => "Apr",
|
||||
"may" => "Mai",
|
||||
"jun" => "Jun",
|
||||
"jul" => "Jul",
|
||||
"aug" => "Aug",
|
||||
"sep" => "Sep",
|
||||
"oct" => "Okt",
|
||||
"nov" => "Nov",
|
||||
"dec" => "Dez",
|
||||
"january" => "Januar",
|
||||
"february" => "Februar",
|
||||
"march" => "März",
|
||||
"april" => "April",
|
||||
"mayl" => "Mai",
|
||||
"june" => "Juni",
|
||||
"july" => "Juli",
|
||||
"august" => "August",
|
||||
"september" => "September",
|
||||
"october" => "Oktober",
|
||||
"november" => "November",
|
||||
"december" => "Dezember",
|
||||
];
|
||||
@@ -3,18 +3,18 @@
|
||||
return [
|
||||
"address_1" => "Adresse 1",
|
||||
"address_2" => "Adresse 2",
|
||||
"admin" => "",
|
||||
"admin" => "Administrator",
|
||||
"city" => "Stadt",
|
||||
"clerk" => "",
|
||||
"clerk" => "Angestellter",
|
||||
"close" => "Schließen",
|
||||
"color" => "",
|
||||
"color" => "Theme-Farben",
|
||||
"comments" => "Kommentare",
|
||||
"common" => "Allgemein",
|
||||
"confirm_search" => "Sie haben eine oder mehrere Zeilen gewählt. Nach der Verarbeitung werden diese nicht mehr ausgewählt sein. Wollen Sie die Suche dennoch verarbeiten?",
|
||||
"copyrights" => "© 2010 - {0}",
|
||||
"correct_errors" => "Bitte korrigieren Sie vor dem Speichern die angezeigten Fehler",
|
||||
"country" => "Land",
|
||||
"dashboard" => "",
|
||||
"dashboard" => "Dashboard",
|
||||
"date" => "Datum",
|
||||
"delete" => "Löschen",
|
||||
"det" => "Details",
|
||||
@@ -26,15 +26,15 @@ return [
|
||||
"export_csv_no" => "Nein",
|
||||
"export_csv_yes" => "Ja",
|
||||
"fields_required_message" => "Die Felder in rot sind erforderlich",
|
||||
"fields_required_message_unique" => "",
|
||||
"fields_required_message_unique" => "Die rot markierten Felder sind erforderlich und müssen eindeutig sein",
|
||||
"first_name" => "Vorname",
|
||||
"first_name_required" => "Vorname ist erforderlich.",
|
||||
"first_page" => "Erste",
|
||||
"gender" => "Geschlecht",
|
||||
"gender_female" => "W",
|
||||
"gender_male" => "M",
|
||||
"gender_undefined" => "",
|
||||
"icon" => "",
|
||||
"gender_undefined" => "Undefiniert",
|
||||
"icon" => "Symbol",
|
||||
"id" => "ID",
|
||||
"import" => "Import",
|
||||
"import_change_file" => "Ändern",
|
||||
@@ -48,21 +48,21 @@ return [
|
||||
"last_page" => "Letzte",
|
||||
"learn_about_project" => "für neueste Nachrichten zum Projekt.",
|
||||
"list_of" => "Liste von",
|
||||
"logo" => "",
|
||||
"logo_mark" => "",
|
||||
"logo" => "Logo",
|
||||
"logo_mark" => "Marke",
|
||||
"logout" => "Ausloggen",
|
||||
"manager" => "",
|
||||
"manager" => "Manager",
|
||||
"migration_needed" => "Eine Datenbankmigration auf {0} wird nach der Anmeldung gestartet.",
|
||||
"new" => "Neu",
|
||||
"no" => "",
|
||||
"no" => "Nein",
|
||||
"no_persons_to_display" => "Keine Personen zum Anzeigen.",
|
||||
"none_selected_text" => "[auswählen]",
|
||||
"or" => "Oder",
|
||||
"people" => "",
|
||||
"people" => "Personen",
|
||||
"phone_number" => "Telefon",
|
||||
"phone_number_required" => "Telefon ist erforderlich",
|
||||
"please_visit_my" => "Bitte beuschen Sie",
|
||||
"position" => "",
|
||||
"position" => "Position",
|
||||
"powered_by" => "Unterstützt von",
|
||||
"price" => "Preis",
|
||||
"print" => "Drucken",
|
||||
@@ -73,8 +73,8 @@ return [
|
||||
"search" => "Suche",
|
||||
"search_options" => "Suchkriterien",
|
||||
"searched_for" => "Gescuht nach",
|
||||
"software_short" => "",
|
||||
"software_title" => "",
|
||||
"software_short" => "OSPOS",
|
||||
"software_title" => "Open Source Point of Sale",
|
||||
"state" => "BL/Kanton",
|
||||
"submit" => "Senden",
|
||||
"total_spent" => "Gesamtausgaben",
|
||||
@@ -83,7 +83,7 @@ return [
|
||||
"website" => "Website",
|
||||
"welcome" => "Willkommen",
|
||||
"welcome_message" => "Willkommen bei OSPOS, zum Beginnen auf ein Modul klicken.",
|
||||
"yes" => "",
|
||||
"yes" => "Ja",
|
||||
"you_are_using_ospos" => "Sie verwenden Open Source Point Of Sale Version",
|
||||
"zip" => "PLZ",
|
||||
];
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"administrator" => "",
|
||||
"administrator" => "Administrator",
|
||||
"basic_information" => "Mitarbeiter-Information",
|
||||
"cannot_be_deleted" => "Konnte gewählten Mitarbeiter nicht löschen, einer oder mehrere weisen Verkäufe aus.",
|
||||
"change_employee" => "",
|
||||
"change_employee" => "Mitarbeiter ändern",
|
||||
"change_password" => "Passwort Ändern",
|
||||
"clerk" => "",
|
||||
"commission" => "",
|
||||
"clerk" => "Angestellter",
|
||||
"commission" => "Provision",
|
||||
"confirm_delete" => "Wollen Sie diesen Mitarbeiter wirklich löschen?",
|
||||
"confirm_restore" => "Möchten Sie die ausgewählten Mitarbeiter wiederherstellen?",
|
||||
"current_password" => "Aktuelles Passwort",
|
||||
"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_admin" => "Sie können keinen Administrator löschen.",
|
||||
"error_updating_admin" => "Sie können keinen Administrator ändern.",
|
||||
"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",
|
||||
"login_info" => "Mitarbeiter Login",
|
||||
"manager" => "",
|
||||
"manager" => "Manager",
|
||||
"new" => "Neuer Mitarbeiter",
|
||||
"none_selected" => "Sie haben keine Mitarbeiter zum Löschen gewählt.",
|
||||
"one_or_multiple" => "Mitarbeiter",
|
||||
|
||||
@@ -26,7 +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_invalid_location" => "Ungültige Lagerorte gefunden: {0}. Nur gültige Lagerorte sind erlaubt.",
|
||||
"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.",
|
||||
|
||||
@@ -146,4 +146,5 @@ return [
|
||||
"used" => "Punkte eingelöst",
|
||||
"work_orders" => "Arbeitsaufträge",
|
||||
"zero_and_less" => "Null und weniger",
|
||||
"toggle_cost_and_profit" => "Kosten & Gewinn umschalten",
|
||||
];
|
||||
|
||||
@@ -222,4 +222,8 @@ return [
|
||||
"work_order_number_duplicate" => "Arbeitsauftragsnummer muss eindeutig sein.",
|
||||
"work_order_sent" => "Arbeitsauftrag gesendet an",
|
||||
"work_order_unsent" => "Der Arbeitsauftrag konnte nicht gesendet werden an",
|
||||
"sale_not_found" => "Verkauf nicht gefunden",
|
||||
"ubl_invoice" => "UBL-Rechnung",
|
||||
"download_ubl" => "UBL-Rechnung herunterladen",
|
||||
"ubl_generation_failed" => "UBL-Rechnung konnte nicht erstellt werden",
|
||||
];
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Είστε βέβαιοι ότι θέλετε να διαγράψετε τα επιλεγμένα χαρακτηριστικά;",
|
||||
"confirm_restore" => "Είστε βέβαιοι ότι θέλετε να επαναφέρετε τα επιλεγμένα χαρακτηριστικά;",
|
||||
"definition_cannot_be_deleted" => "Δεν ήταν δυνατή η διαγραφή των επιλεγμένων χαρακτηριστικών",
|
||||
"definition_invalid_group" => "Η επιλεγμένη ομάδα δεν υπάρχει ή δεν είναι έγκυρη.",
|
||||
"definition_error_adding_updating" => "Το χαρακτηριστικό {0} δεν ήταν δυνατό να προστεθεί ή να ενημερωθεί. Ελέγξτε το αρχείο καταγραφής σφαλμάτων.",
|
||||
"definition_flags" => "Ορατότητα χαρακτηριστικών",
|
||||
"definition_group" => "Ομάδα",
|
||||
|
||||
@@ -6,6 +6,7 @@ return [
|
||||
"confirm_restore" => "Are you sure you want to restore the selected attribute(s)?",
|
||||
"definition_cannot_be_deleted" => "Could not delete selected attribute(s)",
|
||||
"definition_error_adding_updating" => "Attribute {0} could not be added or updated. Please check the error log.",
|
||||
"definition_invalid_group" => "The selected group does not exist or is invalid.",
|
||||
"definition_flags" => "Attribute Visibility",
|
||||
"definition_group" => "Group",
|
||||
"definition_id" => "Id",
|
||||
|
||||
@@ -6,6 +6,7 @@ return [
|
||||
"confirm_restore" => "Are you sure you want to restore the selected attribute(s)?",
|
||||
"definition_cannot_be_deleted" => "Could not delete selected attribute(s)",
|
||||
"definition_error_adding_updating" => "Attribute {0} could not be added or updated. Please check the error log.",
|
||||
"definition_invalid_group" => "The selected group does not exist or is invalid.",
|
||||
"definition_flags" => "Attribute Visibility",
|
||||
"definition_group" => "Group",
|
||||
"definition_id" => "Id",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "¿Está seguro de que desea borrar los atributos seleccionados?",
|
||||
"confirm_restore" => "¿Está seguro de que desea restaurar los atributos seleccionados?",
|
||||
"definition_cannot_be_deleted" => "No se han podido borrar los atributos seleccionados",
|
||||
"definition_invalid_group" => "El grupo seleccionado no existe o no es válido.",
|
||||
"definition_error_adding_updating" => "El atributo {0} no pudo ser agregado o actulizado. Por favor compruebe el registro de errores.",
|
||||
"definition_flags" => "Visibilidad del atributo",
|
||||
"definition_group" => "Grupo",
|
||||
|
||||
49
app/Language/es-ES/Calendar.php
Normal file
49
app/Language/es-ES/Calendar.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"su" => "Do",
|
||||
"mo" => "Lu",
|
||||
"tu" => "Ma",
|
||||
"we" => "Mi",
|
||||
"th" => "Ju",
|
||||
"fr" => "Vi",
|
||||
"sa" => "Sá",
|
||||
"sun" => "Dom",
|
||||
"mon" => "Lun",
|
||||
"tue" => "Mar",
|
||||
"wed" => "Mié",
|
||||
"thu" => "Jue",
|
||||
"fri" => "Vie",
|
||||
"sat" => "Sáb",
|
||||
"sunday" => "Domingo",
|
||||
"monday" => "Lunes",
|
||||
"tuesday" => "Martes",
|
||||
"wednesday" => "Miércoles",
|
||||
"thursday" => "Jueves",
|
||||
"friday" => "Viernes",
|
||||
"saturday" => "Sábado",
|
||||
"jan" => "Ene",
|
||||
"feb" => "Feb",
|
||||
"mar" => "Mar",
|
||||
"apr" => "Abr",
|
||||
"may" => "May",
|
||||
"jun" => "Jun",
|
||||
"jul" => "Jul",
|
||||
"aug" => "Ago",
|
||||
"sep" => "Sep",
|
||||
"oct" => "Oct",
|
||||
"nov" => "Nov",
|
||||
"dec" => "Dic",
|
||||
"january" => "Enero",
|
||||
"february" => "Febrero",
|
||||
"march" => "Marzo",
|
||||
"april" => "Abril",
|
||||
"mayl" => "Mayo",
|
||||
"june" => "Junio",
|
||||
"july" => "Julio",
|
||||
"august" => "Agosto",
|
||||
"september" => "Septiembre",
|
||||
"october" => "Octubre",
|
||||
"november" => "Noviembre",
|
||||
"december" => "Diciembre",
|
||||
];
|
||||
@@ -14,8 +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_admin" => "No puedes eliminar un usuario administrador.",
|
||||
"error_updating_admin" => "No puedes modificar un usuario administrador.",
|
||||
"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,7 +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_invalid_location" => "Ubicación(es) de stock inválida(s) encontrada(s): {0}. Solo ubicaciones de stock válidas son permitidas.",
|
||||
"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.",
|
||||
|
||||
@@ -146,4 +146,5 @@ return [
|
||||
"used" => "Puntos usados",
|
||||
"work_orders" => "Ordenes",
|
||||
"zero_and_less" => "Cero y negativos",
|
||||
"toggle_cost_and_profit" => "Alternar Costo y Ganancia",
|
||||
];
|
||||
|
||||
@@ -222,5 +222,9 @@ return [
|
||||
"work_order_number_duplicate" => "El numero de orden de trabajo debe ser unico.",
|
||||
"work_order_sent" => "Orden de trabajo enviada a",
|
||||
"work_order_unsent" => "Orden de trabajo fallida al enviar a",
|
||||
"sale_not_found" => "Venta no encontrada",
|
||||
"ubl_invoice" => "Factura UBL",
|
||||
"download_ubl" => "Descargar Factura UBL",
|
||||
"ubl_generation_failed" => "Error al generar la factura UBL",
|
||||
"selected_customer" => "Cliente seleccionado",
|
||||
];
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "¿Está seguro de eliminar el/los atributo(s) seleccionado(s)?",
|
||||
"confirm_restore" => "¿Está seguro que quiere restaurar los atributos seleccionados?",
|
||||
"definition_cannot_be_deleted" => "No ha sido posible eliminar el/los atributo(s) seleccionado(s)",
|
||||
"definition_invalid_group" => "El grupo seleccionado no existe o no es válido.",
|
||||
"definition_error_adding_updating" => "El atributo {0} no pudo ser agregado o actualizado. Favor de revisar el registro de errorres.",
|
||||
"definition_flags" => "Visibilidad del atributo",
|
||||
"definition_group" => "Grupo",
|
||||
|
||||
49
app/Language/es-MX/Calendar.php
Normal file
49
app/Language/es-MX/Calendar.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"su" => "Do",
|
||||
"mo" => "Lu",
|
||||
"tu" => "Ma",
|
||||
"we" => "Mi",
|
||||
"th" => "Ju",
|
||||
"fr" => "Vi",
|
||||
"sa" => "Sá",
|
||||
"sun" => "Dom",
|
||||
"mon" => "Lun",
|
||||
"tue" => "Mar",
|
||||
"wed" => "Mié",
|
||||
"thu" => "Jue",
|
||||
"fri" => "Vie",
|
||||
"sat" => "Sáb",
|
||||
"sunday" => "Domingo",
|
||||
"monday" => "Lunes",
|
||||
"tuesday" => "Martes",
|
||||
"wednesday" => "Miércoles",
|
||||
"thursday" => "Jueves",
|
||||
"friday" => "Viernes",
|
||||
"saturday" => "Sábado",
|
||||
"jan" => "Ene",
|
||||
"feb" => "Feb",
|
||||
"mar" => "Mar",
|
||||
"apr" => "Abr",
|
||||
"may" => "May",
|
||||
"jun" => "Jun",
|
||||
"jul" => "Jul",
|
||||
"aug" => "Ago",
|
||||
"sep" => "Sep",
|
||||
"oct" => "Oct",
|
||||
"nov" => "Nov",
|
||||
"dec" => "Dic",
|
||||
"january" => "Enero",
|
||||
"february" => "Febrero",
|
||||
"march" => "Marzo",
|
||||
"april" => "Abril",
|
||||
"mayl" => "Mayo",
|
||||
"june" => "Junio",
|
||||
"july" => "Julio",
|
||||
"august" => "Agosto",
|
||||
"september" => "Septiembre",
|
||||
"october" => "Octubre",
|
||||
"november" => "Noviembre",
|
||||
"december" => "Diciembre",
|
||||
];
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "آیا مطمئن هستید که می خواهید ویژگی (های) انتخاب شده را حذف کنید؟",
|
||||
"confirm_restore" => "آیا مطمئن هستید که می خواهید ویژگی (های) انتخاب شده را بازیابی کنید؟",
|
||||
"definition_cannot_be_deleted" => "نمی توان ویژگی (های) انتخابی را حذف کرد",
|
||||
"definition_invalid_group" => "گروه انتخاب شده وجود ندارد یا نامعتبر است.",
|
||||
"definition_error_adding_updating" => "ویژگی{0} اضافه نشد یا به روز نمی شود. لطفا گزارش خطا را بررسی کنید.",
|
||||
"definition_flags" => "قابلیت مشاهده ویژگی",
|
||||
"definition_group" => "گروه",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Êtes-vous certain de vouloir supprimer le(s) attribut(s) sélectionné(s) ?",
|
||||
"confirm_restore" => "Êtes-vous certain de vouloir restaurer le(s) attribut(s) sélectionné(s) ?",
|
||||
"definition_cannot_be_deleted" => "Le(s) attribut(s) sélectionné(s) n'ont pas pu être supprimé(s)",
|
||||
"definition_invalid_group" => "Le groupe sélectionné n'existe pas ou est invalide.",
|
||||
"definition_error_adding_updating" => "L'attribut {0} n'a pas pu être ajouté ou mis à jour. Veuillez vérifier le journal d'erreurs.",
|
||||
"definition_flags" => "Visibilité de l'attribut",
|
||||
"definition_group" => "Groupe",
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
return [
|
||||
"address_1" => "Adresse 1",
|
||||
"address_2" => "Adresse 2",
|
||||
"admin" => "",
|
||||
"admin" => "Administrateur",
|
||||
"city" => "Ville",
|
||||
"clerk" => "",
|
||||
"clerk" => "Employé",
|
||||
"close" => "Fermer",
|
||||
"color" => "",
|
||||
"color" => "Couleurs du thème",
|
||||
"comments" => "Commentaires",
|
||||
"common" => "commun",
|
||||
"confirm_search" => "Vous avez sélectionné une ou plusieurs lignes, celles-ci ne seront plus sélectionnées après votre recherche. Voulez-vous continuer ?",
|
||||
"copyrights" => "© 2010 - {0}",
|
||||
"correct_errors" => "Merci de corriger les erreurs identifiées avant d'enregistrer",
|
||||
"country" => "Pays",
|
||||
"dashboard" => "",
|
||||
"dashboard" => "Tableau de bord",
|
||||
"date" => "Date",
|
||||
"delete" => "Supprimer",
|
||||
"det" => "détails",
|
||||
@@ -26,14 +26,14 @@ return [
|
||||
"export_csv_no" => "Non",
|
||||
"export_csv_yes" => "Oui",
|
||||
"fields_required_message" => "Les champs en rouge sont requis",
|
||||
"fields_required_message_unique" => "",
|
||||
"fields_required_message_unique" => "Les champs en rouge sont requis et doivent être uniques",
|
||||
"first_name" => "Prénom",
|
||||
"first_name_required" => "Le prénom est requis.",
|
||||
"first_page" => "Premier",
|
||||
"gender" => "Genre",
|
||||
"gender_female" => "F",
|
||||
"gender_male" => "M",
|
||||
"gender_undefined" => "",
|
||||
"gender_undefined" => "Non défini",
|
||||
"icon" => "Icône",
|
||||
"id" => "Identifiant",
|
||||
"import" => "Importation",
|
||||
@@ -51,18 +51,18 @@ return [
|
||||
"logo" => "Logo",
|
||||
"logo_mark" => "Marque",
|
||||
"logout" => "Déconnexion",
|
||||
"manager" => "",
|
||||
"manager" => "Gestionnaire",
|
||||
"migration_needed" => "Une migration de la base de donnée vers {0} démarrera après le connexion.",
|
||||
"new" => "Nouveau",
|
||||
"no" => "Oui",
|
||||
"no" => "Non",
|
||||
"no_persons_to_display" => "Il n'y a personne à afficher.",
|
||||
"none_selected_text" => "[Sélectionner]",
|
||||
"or" => "OU",
|
||||
"people" => "",
|
||||
"people" => "Personnes",
|
||||
"phone_number" => "Téléphone",
|
||||
"phone_number_required" => "Le numéro de téléphone est requis.",
|
||||
"please_visit_my" => "SVP visitez le",
|
||||
"position" => "",
|
||||
"position" => "Position",
|
||||
"powered_by" => "Propulsé par",
|
||||
"price" => "Prix",
|
||||
"print" => "Imprimer",
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"administrator" => "",
|
||||
"administrator" => "Administrateur",
|
||||
"basic_information" => "Fiche",
|
||||
"cannot_be_deleted" => "Impossible de supprimer le(s) employé(s) sélectionné(s),car un ou plusieur a éffectué une vente, ou car vous essayez de vous supprimer vous-meme.",
|
||||
"change_employee" => "",
|
||||
"change_employee" => "Changer d'employé",
|
||||
"change_password" => "Changement de mot de passe",
|
||||
"clerk" => "",
|
||||
"commission" => "",
|
||||
"clerk" => "Employé",
|
||||
"commission" => "Commission",
|
||||
"confirm_delete" => "Êtes-vous certain de vouloir supprimer le(s) employé(s) sélectionné(s) ?",
|
||||
"confirm_restore" => "Êtes-vous certain de vouloir restaurer le(s) employé(s) selectionné(s) ?",
|
||||
"current_password" => "Mot de passe actuel",
|
||||
"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_admin" => "Vous ne pouvez pas supprimer un utilisateur administrateur.",
|
||||
"error_updating_admin" => "Vous ne pouvez pas modifier un utilisateur administrateur.",
|
||||
"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",
|
||||
"login_info" => "Connexion",
|
||||
"manager" => "",
|
||||
"manager" => "Gestionnaire",
|
||||
"new" => "Nouvel employé",
|
||||
"none_selected" => "Aucun employé sélectionné pour la suppression.",
|
||||
"one_or_multiple" => "employé(s)",
|
||||
|
||||
@@ -26,7 +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_invalid_location" => "Emplacement(s) de stock invalide(s) trouvé(s) : {0}. Seuls les emplacements de stock valides sont autorisés.",
|
||||
"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.",
|
||||
|
||||
@@ -146,4 +146,5 @@ return [
|
||||
"used" => "Points utilisés",
|
||||
"work_orders" => "Ordre Du Travail",
|
||||
"zero_and_less" => "Zéro ou moin",
|
||||
"toggle_cost_and_profit" => "Basculer Coût & Bénéfice",
|
||||
];
|
||||
|
||||
@@ -222,4 +222,8 @@ return [
|
||||
"work_order_number_duplicate" => "Le numéro de bon de travail doit être unique.",
|
||||
"work_order_sent" => "Ordre de travail envoyé à",
|
||||
"work_order_unsent" => "L'ordre de travail n'a pas pu être envoyé à",
|
||||
"sale_not_found" => "Vente introuvable",
|
||||
"ubl_invoice" => "Facture UBL",
|
||||
"download_ubl" => "Télécharger Facture UBL",
|
||||
"ubl_generation_failed" => "Échec de la génération de la facture UBL",
|
||||
];
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "האם אתה בטוח שברצונך למחוק את המאפיינים שנבחרו?",
|
||||
"confirm_restore" => "האם אתה בטוח שברצונך לשחזר את המאפיינים שנבחרו?",
|
||||
"definition_cannot_be_deleted" => "לא ניתן למחוק מאפיינים נבחר(ים)",
|
||||
"definition_invalid_group" => "הקבוצה שנבחרה לא קיימת או אינה תקינה.",
|
||||
"definition_error_adding_updating" => "לא ניתן להוסיף או לעדכן את הערך {0}. בדוק את יומן השגיאות.",
|
||||
"definition_flags" => "מאפיין גלוי",
|
||||
"definition_group" => "קבוצה",
|
||||
|
||||
49
app/Language/he/Calendar.php
Normal file
49
app/Language/he/Calendar.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"su" => "א",
|
||||
"mo" => "ב",
|
||||
"tu" => "ג",
|
||||
"we" => "ד",
|
||||
"th" => "ה",
|
||||
"fr" => "ו",
|
||||
"sa" => "ש",
|
||||
"sun" => "יום א",
|
||||
"mon" => "יום ב",
|
||||
"tue" => "יום ג",
|
||||
"wed" => "יום ד",
|
||||
"thu" => "יום ה",
|
||||
"fri" => "יום ו",
|
||||
"sat" => "שבת",
|
||||
"sunday" => "יום ראשון",
|
||||
"monday" => "יום שני",
|
||||
"tuesday" => "יום שלישי",
|
||||
"wednesday" => "יום רביעי",
|
||||
"thursday" => "יום חמישי",
|
||||
"friday" => "יום שישי",
|
||||
"saturday" => "יום שבת",
|
||||
"jan" => "ינו",
|
||||
"feb" => "פבר",
|
||||
"mar" => "מרץ",
|
||||
"apr" => "אפר",
|
||||
"may" => "מאי",
|
||||
"jun" => "יונ",
|
||||
"jul" => "יול",
|
||||
"aug" => "אוג",
|
||||
"sep" => "ספט",
|
||||
"oct" => "אוק",
|
||||
"nov" => "נוב",
|
||||
"dec" => "דצמ",
|
||||
"january" => "ינואר",
|
||||
"february" => "פברואר",
|
||||
"march" => "מרץ",
|
||||
"april" => "אפריל",
|
||||
"mayl" => "מאי",
|
||||
"june" => "יוני",
|
||||
"july" => "יולי",
|
||||
"august" => "אוגוסט",
|
||||
"september" => "ספטמבר",
|
||||
"october" => "אוקטובר",
|
||||
"november" => "נובמבר",
|
||||
"december" => "דצמבר",
|
||||
];
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "",
|
||||
"confirm_restore" => "",
|
||||
"definition_cannot_be_deleted" => "",
|
||||
"definition_invalid_group" => "",
|
||||
"definition_error_adding_updating" => "",
|
||||
"definition_flags" => "",
|
||||
"definition_group" => "",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Biztosan törli szeretné a kijelölt tulajdonságokat?",
|
||||
"confirm_restore" => "Biztosan visszaállítja a kijelölt tulajdonságokat?",
|
||||
"definition_cannot_be_deleted" => "Nem sikerült törölni a kijelölt tulajdonságokat",
|
||||
"definition_invalid_group" => "A kiválasztott csoport nem létezik vagy érvénytelen.",
|
||||
"definition_error_adding_updating" => "{0} attribútum nem adható hozzá és nem frissíthető. Kérjük, ellenőrizze a hibanaplót.",
|
||||
"definition_flags" => "Tulajdonság láthatósága",
|
||||
"definition_group" => "Csoport",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Are you sure you want to delete the selected attribute(s)?",
|
||||
"confirm_restore" => "Are you sure you want to restore the selected attribute(s)?",
|
||||
"definition_cannot_be_deleted" => "Could not delete selected attribute(s)",
|
||||
"definition_invalid_group" => "",
|
||||
"definition_error_adding_updating" => "Attribute {0} could not be added or updated. Please check the error log.",
|
||||
"definition_flags" => "Attribute Visibility",
|
||||
"definition_group" => "Group",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Apakah Anda yakin ingin menghapus atribut tersebut?",
|
||||
"confirm_restore" => "Apakah Anda yakin ingin mengembalikan atribut tersebut?",
|
||||
"definition_cannot_be_deleted" => "Tidak bisa menghapus atribut terpilih",
|
||||
"definition_invalid_group" => "Grup yang dipilih tidak ada atau tidak valid.",
|
||||
"definition_error_adding_updating" => "Atribut {0} tidak dapat ditambah atau diperbaharui. Silahkan periksa log kesalahan.",
|
||||
"definition_flags" => "Visibilitas Atribut",
|
||||
"definition_group" => "Grup",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Sei sicuro di voler eliminare gli attributi selezionati?",
|
||||
"confirm_restore" => "Sei sicuro di voler ripristinare l'attributo selezionato?",
|
||||
"definition_cannot_be_deleted" => "Non riesco a cancellare l'attributo selezionato",
|
||||
"definition_invalid_group" => "Il gruppo selezionato non esiste o non è valido.",
|
||||
"definition_error_adding_updating" => "Impossibile aggiungere o aggiornare l'attributo {0}. Si prega di controllare il registro degli errori.",
|
||||
"definition_flags" => "Visibilità attributo",
|
||||
"definition_group" => "Gruppo",
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
return [
|
||||
"address_1" => "Indirizzo 1",
|
||||
"address_2" => "Indirizzo 2",
|
||||
"admin" => "",
|
||||
"admin" => "Amministratore",
|
||||
"city" => "Città",
|
||||
"clerk" => "",
|
||||
"clerk" => "Impiegato",
|
||||
"close" => "Chiudere",
|
||||
"color" => "",
|
||||
"color" => "Colori del tema",
|
||||
"comments" => "Commenti",
|
||||
"common" => "comune",
|
||||
"confirm_search" => "Hai selezionato una o più righe, queste non saranno più selezionate dopo la tua ricerca. Sei sicuro di voler procedere alla ricerca?",
|
||||
"copyrights" => "© 2010 - {0}",
|
||||
"correct_errors" => "Correggi gli errori identificati prima di salvare",
|
||||
"country" => "Paese",
|
||||
"dashboard" => "",
|
||||
"dashboard" => "Pannello di controllo",
|
||||
"date" => "Data",
|
||||
"delete" => "Cancella",
|
||||
"det" => "dettagli",
|
||||
@@ -26,14 +26,14 @@ return [
|
||||
"export_csv_no" => "No",
|
||||
"export_csv_yes" => "Si",
|
||||
"fields_required_message" => "I campi in rosso sono richiesti",
|
||||
"fields_required_message_unique" => "",
|
||||
"fields_required_message_unique" => "I campi in rosso sono richiesti e devono essere unici",
|
||||
"first_name" => "Nome",
|
||||
"first_name_required" => "Campo Nome è richiesto.",
|
||||
"first_page" => "Primo",
|
||||
"gender" => "Sesso",
|
||||
"gender_female" => "F",
|
||||
"gender_male" => "M",
|
||||
"gender_undefined" => "",
|
||||
"gender_undefined" => "Non definito",
|
||||
"icon" => "Icona",
|
||||
"id" => "ID",
|
||||
"import" => "Importa",
|
||||
@@ -51,18 +51,18 @@ return [
|
||||
"logo" => "Logo",
|
||||
"logo_mark" => "Marchio",
|
||||
"logout" => "Esci",
|
||||
"manager" => "",
|
||||
"migration_needed" => "",
|
||||
"manager" => "Responsabile",
|
||||
"migration_needed" => "Una migrazione del database verso {0} inizierà dopo l'accesso.",
|
||||
"new" => "Nuovo",
|
||||
"no" => "",
|
||||
"no" => "No",
|
||||
"no_persons_to_display" => "Non ci sono persone da mostrare.",
|
||||
"none_selected_text" => "[Selezionare]",
|
||||
"or" => "OR",
|
||||
"people" => "",
|
||||
"people" => "Persone",
|
||||
"phone_number" => "Numero di Telefono",
|
||||
"phone_number_required" => "",
|
||||
"phone_number_required" => "Il numero di telefono è richiesto",
|
||||
"please_visit_my" => "Visitare il",
|
||||
"position" => "",
|
||||
"position" => "Posizione",
|
||||
"powered_by" => "Sviluppato da",
|
||||
"price" => "Prezzo",
|
||||
"print" => "Stampa",
|
||||
@@ -83,7 +83,7 @@ return [
|
||||
"website" => "Sito web",
|
||||
"welcome" => "Benvenuto",
|
||||
"welcome_message" => "Benvenuto in OSPOS, clicca un modulo sottostante per incominciare.",
|
||||
"yes" => "",
|
||||
"yes" => "Sì",
|
||||
"you_are_using_ospos" => "Stai usando la versione Open Source Point Of Sale (Punto di vendita)",
|
||||
"zip" => "CAP",
|
||||
];
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"administrator" => "",
|
||||
"administrator" => "Amministratore",
|
||||
"basic_information" => "Informazioni",
|
||||
"cannot_be_deleted" => "Eliminazione dell'impiegato/i non consentita, uno o più hanno trattato delle vendite o stai cancellando il tuo account.",
|
||||
"change_employee" => "",
|
||||
"change_employee" => "Cambia Impiegato",
|
||||
"change_password" => "Cambia Password",
|
||||
"clerk" => "",
|
||||
"commission" => "",
|
||||
"clerk" => "Impiegato",
|
||||
"commission" => "Commissione",
|
||||
"confirm_delete" => "Sei sicuro di voler eliminare l'impiegato/i selezionato?",
|
||||
"confirm_restore" => "Sei sicuro di voler ripristinare gl'Impiegati selezionati?",
|
||||
"current_password" => "Password Corrente",
|
||||
"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_admin" => "Non puoi eliminare un utente amministratore.",
|
||||
"error_updating_admin" => "Non puoi modificare un utente amministratore.",
|
||||
"error_deleting_demo_admin" => "Non puoi eliminare l'utente admin demo.",
|
||||
"error_updating_demo_admin" => "Non puoi cambiare l'utente admin demo.",
|
||||
"language" => "Lingua",
|
||||
"login_info" => "Login",
|
||||
"manager" => "",
|
||||
"manager" => "Manager",
|
||||
"new" => "Nuovo Impiegato",
|
||||
"none_selected" => "Non hai selezionato nessun impiegato da eliminare.",
|
||||
"one_or_multiple" => "impiegato/i",
|
||||
|
||||
@@ -26,7 +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_invalid_location" => "Trovata/e locazione/i di stock non valida/e: {0}. Solo le locazioni di stock valide sono ammesse.",
|
||||
"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.",
|
||||
|
||||
@@ -146,4 +146,5 @@ return [
|
||||
"used" => "Punti Usati",
|
||||
"work_orders" => "Ordini di lavoro",
|
||||
"zero_and_less" => "Zero e meno",
|
||||
"toggle_cost_and_profit" => "Commuta Costo & Profitto",
|
||||
];
|
||||
|
||||
@@ -222,4 +222,8 @@ return [
|
||||
"work_order_number_duplicate" => "Numero Ordine di Lavoro deve essere unico.",
|
||||
"work_order_sent" => "Ordine di lavoro inviato",
|
||||
"work_order_unsent" => "Ordine di Lavoro fallito da inviare a",
|
||||
"sale_not_found" => "Vendita non trovata",
|
||||
"ubl_invoice" => "Fattura UBL",
|
||||
"download_ubl" => "Scarica fattura UBL",
|
||||
"ubl_generation_failed" => "Impossibile generare la fattura UBL",
|
||||
];
|
||||
|
||||
49
app/Language/ka/Calendar.php
Normal file
49
app/Language/ka/Calendar.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"su" => "",
|
||||
"mo" => "",
|
||||
"tu" => "",
|
||||
"we" => "",
|
||||
"th" => "",
|
||||
"fr" => "",
|
||||
"sa" => "",
|
||||
"sun" => "",
|
||||
"mon" => "",
|
||||
"tue" => "",
|
||||
"wed" => "",
|
||||
"thu" => "",
|
||||
"fri" => "",
|
||||
"sat" => "",
|
||||
"sunday" => "",
|
||||
"monday" => "",
|
||||
"tuesday" => "",
|
||||
"wednesday" => "",
|
||||
"thursday" => "",
|
||||
"friday" => "",
|
||||
"saturday" => "",
|
||||
"jan" => "",
|
||||
"feb" => "",
|
||||
"mar" => "",
|
||||
"apr" => "",
|
||||
"may" => "",
|
||||
"jun" => "",
|
||||
"jul" => "",
|
||||
"aug" => "",
|
||||
"sep" => "",
|
||||
"oct" => "",
|
||||
"nov" => "",
|
||||
"dec" => "",
|
||||
"january" => "",
|
||||
"february" => "",
|
||||
"march" => "",
|
||||
"april" => "",
|
||||
"mayl" => "",
|
||||
"june" => "",
|
||||
"july" => "",
|
||||
"august" => "",
|
||||
"september" => "",
|
||||
"october" => "",
|
||||
"november" => "",
|
||||
"december" => "",
|
||||
];
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "តើអ្នកពិតជាចង់លុប ព៌តមានបន្ថែម ដែលបានជ្រើសរើស?",
|
||||
"confirm_restore" => "តើអ្នកពិតជាដាក់ឡើងវិញនៅ ព៌តមានបន្ថែម ដែលបានជ្រើសរើស?",
|
||||
"definition_cannot_be_deleted" => "មិនអាចលុបព៌តមានបន្ថែមដែលបានជ្រើសរើស",
|
||||
"definition_invalid_group" => "",
|
||||
"definition_error_adding_updating" => "ព៌តមានបន្ថែម {0} មិនអាចថែម រឺកែប្រែបានឡើយ។ សូមចូលទៅឆែករបាយការណ៍កំហុស។",
|
||||
"definition_flags" => "ដាក់បង្ហាញព៌តមានបន្ថែម",
|
||||
"definition_group" => "ក្រុម",
|
||||
|
||||
@@ -222,4 +222,5 @@ return [
|
||||
"work_order_number_duplicate" => "",
|
||||
"work_order_sent" => "",
|
||||
"work_order_unsent" => "",
|
||||
"sale_not_found" => "",
|
||||
];
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "ແນ່ໃຈຫຼືບໍທີ່ຈະລືບລາຍການທີ່ເລືອກ",
|
||||
"confirm_restore" => "ແນ່ໃຈຫຼືບໍທີ່ຈະຄືນຄ່າແອັດທິບິ້ວດັ່ງກ່າວ?",
|
||||
"definition_cannot_be_deleted" => "ບໍສາມາດລືບລາຍການທີ່ເລືອກໄດ້",
|
||||
"definition_invalid_group" => "",
|
||||
"definition_error_adding_updating" => "ລາຍການ {0} ບໍສາມາດເພີ່ມ ຫຼື ແກ້ໄຂ. ກະລຸນາກວດສອບຢູ່ log ຂໍ້ຜິດຜາດ",
|
||||
"definition_flags" => "ຄູນສົມບັດການເບິ່ງເຫັນ",
|
||||
"definition_group" => "ກຸ່ມ",
|
||||
|
||||
49
app/Language/lo/Calendar.php
Normal file
49
app/Language/lo/Calendar.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"su" => "",
|
||||
"mo" => "",
|
||||
"tu" => "",
|
||||
"we" => "",
|
||||
"th" => "",
|
||||
"fr" => "",
|
||||
"sa" => "",
|
||||
"sun" => "",
|
||||
"mon" => "",
|
||||
"tue" => "",
|
||||
"wed" => "",
|
||||
"thu" => "",
|
||||
"fri" => "",
|
||||
"sat" => "",
|
||||
"sunday" => "",
|
||||
"monday" => "",
|
||||
"tuesday" => "",
|
||||
"wednesday" => "",
|
||||
"thursday" => "",
|
||||
"friday" => "",
|
||||
"saturday" => "",
|
||||
"jan" => "",
|
||||
"feb" => "",
|
||||
"mar" => "",
|
||||
"apr" => "",
|
||||
"may" => "",
|
||||
"jun" => "",
|
||||
"jul" => "",
|
||||
"aug" => "",
|
||||
"sep" => "",
|
||||
"oct" => "",
|
||||
"nov" => "",
|
||||
"dec" => "",
|
||||
"january" => "",
|
||||
"february" => "",
|
||||
"march" => "",
|
||||
"april" => "",
|
||||
"mayl" => "",
|
||||
"june" => "",
|
||||
"july" => "",
|
||||
"august" => "",
|
||||
"september" => "",
|
||||
"october" => "",
|
||||
"november" => "",
|
||||
"december" => "",
|
||||
];
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Are you sure you want to delete the selected attribute(s)?",
|
||||
"confirm_restore" => "",
|
||||
"definition_cannot_be_deleted" => "Could not delete selected attribute(s)",
|
||||
"definition_invalid_group" => "",
|
||||
"definition_error_adding_updating" => "",
|
||||
"definition_flags" => "Attribute Visibility",
|
||||
"definition_group" => "Group",
|
||||
|
||||
49
app/Language/ml/Calendar.php
Normal file
49
app/Language/ml/Calendar.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"su" => "ഞാ",
|
||||
"mo" => "തി",
|
||||
"tu" => "ചൊ",
|
||||
"we" => "ബു",
|
||||
"th" => "വ്യാ",
|
||||
"fr" => "വെ",
|
||||
"sa" => "ശ",
|
||||
"sun" => "ഞായർ",
|
||||
"mon" => "തിങ്കൾ",
|
||||
"tue" => "ചൊവ്വ",
|
||||
"wed" => "ബുധൻ",
|
||||
"thu" => "വ്യാഴം",
|
||||
"fri" => "വെള്ളി",
|
||||
"sat" => "ശനി",
|
||||
"sunday" => "ഞായറാഴ്ച",
|
||||
"monday" => "തിങ്കളാഴ്ച",
|
||||
"tuesday" => "ചൊവ്വാഴ്ച",
|
||||
"wednesday" => "ബുധനാഴ്ച",
|
||||
"thursday" => "വ്യാഴാഴ്ച",
|
||||
"friday" => "വെള്ളിയാഴ്ച",
|
||||
"saturday" => "ശനിയാഴ്ച",
|
||||
"jan" => "ജനു",
|
||||
"feb" => "ഫെബ്രു",
|
||||
"mar" => "മാർ",
|
||||
"apr" => "ഏപ്രി",
|
||||
"may" => "മേയ്",
|
||||
"jun" => "ജൂൺ",
|
||||
"jul" => "ജൂലൈ",
|
||||
"aug" => "ആഗ",
|
||||
"sep" => "സെപ്റ്റം",
|
||||
"oct" => "ഒക്ടോ",
|
||||
"nov" => "നവം",
|
||||
"dec" => "ഡിസം",
|
||||
"january" => "ജനുവരി",
|
||||
"february" => "ഫെബ്രുവരി",
|
||||
"march" => "മാർച്ച്",
|
||||
"april" => "ഏപ്രിൽ",
|
||||
"mayl" => "മേയ്",
|
||||
"june" => "ജൂൺ",
|
||||
"july" => "ജൂലൈ",
|
||||
"august" => "ആഗസ്റ്റ്",
|
||||
"september" => "സെപ്റ്റംബർ",
|
||||
"october" => "ഒക്ടോബർ",
|
||||
"november" => "നവംബർ",
|
||||
"december" => "ഡിസംബർ",
|
||||
];
|
||||
@@ -222,4 +222,5 @@ return [
|
||||
"work_order_number_duplicate" => "",
|
||||
"work_order_sent" => "",
|
||||
"work_order_unsent" => "",
|
||||
"sale_not_found" => "",
|
||||
];
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Are you sure you want to delete the selected attribute(s)?",
|
||||
"confirm_restore" => "Are you sure you want to restore the selected attribute(s)?",
|
||||
"definition_cannot_be_deleted" => "Could not delete selected attribute(s)",
|
||||
"definition_invalid_group" => "",
|
||||
"definition_error_adding_updating" => "Attribute {0} could not be added or updated. Please check the error log.",
|
||||
"definition_flags" => "Attribute Visibility",
|
||||
"definition_group" => "Group",
|
||||
|
||||
49
app/Language/nb/Calendar.php
Normal file
49
app/Language/nb/Calendar.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"su" => "Sø",
|
||||
"mo" => "Ma",
|
||||
"tu" => "Ti",
|
||||
"we" => "On",
|
||||
"th" => "To",
|
||||
"fr" => "Fr",
|
||||
"sa" => "Lø",
|
||||
"sun" => "Søn",
|
||||
"mon" => "Man",
|
||||
"tue" => "Tir",
|
||||
"wed" => "Ons",
|
||||
"thu" => "Tor",
|
||||
"fri" => "Fre",
|
||||
"sat" => "Lør",
|
||||
"sunday" => "Søndag",
|
||||
"monday" => "Mandag",
|
||||
"tuesday" => "Tirsdag",
|
||||
"wednesday" => "Onsdag",
|
||||
"thursday" => "Torsdag",
|
||||
"friday" => "Fredag",
|
||||
"saturday" => "Lørdag",
|
||||
"jan" => "Jan",
|
||||
"feb" => "Feb",
|
||||
"mar" => "Mar",
|
||||
"apr" => "Apr",
|
||||
"may" => "Mai",
|
||||
"jun" => "Jun",
|
||||
"jul" => "Jul",
|
||||
"aug" => "Aug",
|
||||
"sep" => "Sep",
|
||||
"oct" => "Okt",
|
||||
"nov" => "Nov",
|
||||
"dec" => "Des",
|
||||
"january" => "Januar",
|
||||
"february" => "Februar",
|
||||
"march" => "Mars",
|
||||
"april" => "April",
|
||||
"mayl" => "Mai",
|
||||
"june" => "Juni",
|
||||
"july" => "Juli",
|
||||
"august" => "August",
|
||||
"september" => "September",
|
||||
"october" => "Oktober",
|
||||
"november" => "November",
|
||||
"december" => "Desember",
|
||||
];
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Bent u zeker dat u de geselecteerde attributen wil verwijderen?",
|
||||
"confirm_restore" => "Bent u zeker dat u de geselecteerde attributen wil herstellen?",
|
||||
"definition_cannot_be_deleted" => "De geselecteerde attributen konden niet verwijderd worden",
|
||||
"definition_invalid_group" => "De geselecteerde groep bestaat niet of is ongeldig.",
|
||||
"definition_error_adding_updating" => "Attribuut {0} kon niet toegevoegd of gewijzigd worden. Kijk de error logs na.",
|
||||
"definition_flags" => "Zichtbaarheid",
|
||||
"definition_group" => "Groep",
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Weet u zeker dat u de geselecteerde kenmerken wilt verwijderen?",
|
||||
"confirm_restore" => "Weet u zeker dat u de geselecteerde kenmerken wilt herstellen?",
|
||||
"definition_cannot_be_deleted" => "Kan geselecteerde kenmerk(en) niet verwijderen",
|
||||
"definition_invalid_group" => "De geselecteerde groep bestaat niet of is ongeldig.",
|
||||
"definition_error_adding_updating" => "Kenmerk {0} kan niet worden toegevoegd of bijgewerkt. Bekijk het foutenlogboek.",
|
||||
"definition_flags" => "Kenmerk zichtbaarheid",
|
||||
"definition_group" => "Groep",
|
||||
|
||||
49
app/Language/nl-NL/Calendar.php
Normal file
49
app/Language/nl-NL/Calendar.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"su" => "Zo",
|
||||
"mo" => "Ma",
|
||||
"tu" => "Di",
|
||||
"we" => "Wo",
|
||||
"th" => "Do",
|
||||
"fr" => "Vr",
|
||||
"sa" => "Za",
|
||||
"sun" => "Zon",
|
||||
"mon" => "Maa",
|
||||
"tue" => "Din",
|
||||
"wed" => "Woe",
|
||||
"thu" => "Don",
|
||||
"fri" => "Vri",
|
||||
"sat" => "Zat",
|
||||
"sunday" => "Zondag",
|
||||
"monday" => "Maandag",
|
||||
"tuesday" => "Dinsdag",
|
||||
"wednesday" => "Woensdag",
|
||||
"thursday" => "Donderdag",
|
||||
"friday" => "Vrijdag",
|
||||
"saturday" => "Zaterdag",
|
||||
"jan" => "Jan",
|
||||
"feb" => "Feb",
|
||||
"mar" => "Maa",
|
||||
"apr" => "Apr",
|
||||
"may" => "Mei",
|
||||
"jun" => "Jun",
|
||||
"jul" => "Jul",
|
||||
"aug" => "Aug",
|
||||
"sep" => "Sep",
|
||||
"oct" => "Okt",
|
||||
"nov" => "Nov",
|
||||
"dec" => "Dec",
|
||||
"january" => "Januari",
|
||||
"february" => "Februari",
|
||||
"march" => "Maart",
|
||||
"april" => "April",
|
||||
"mayl" => "Mei",
|
||||
"june" => "Juni",
|
||||
"july" => "Juli",
|
||||
"august" => "Augustus",
|
||||
"september" => "September",
|
||||
"october" => "Oktober",
|
||||
"november" => "November",
|
||||
"december" => "December",
|
||||
];
|
||||
@@ -3,18 +3,18 @@
|
||||
return [
|
||||
"address_1" => "Adres 1",
|
||||
"address_2" => "Adres 2",
|
||||
"admin" => "",
|
||||
"admin" => "Beheerder",
|
||||
"city" => "Plaats",
|
||||
"clerk" => "",
|
||||
"clerk" => "Bediende",
|
||||
"close" => "Sluiten",
|
||||
"color" => "",
|
||||
"color" => "Thema-kleuren",
|
||||
"comments" => "Opmerkingen",
|
||||
"common" => "algemeen",
|
||||
"confirm_search" => "U heeft één of meerdere rijen geselecteerd, deze zullen niet langer geselecteerd zijn na uw zoekopdracht. Weet u zeker dat u deze zoekopdracht wilt verzenden?",
|
||||
"copyrights" => "© 2010 - {0}",
|
||||
"correct_errors" => "Geïdentificeerd fouten oplossen voor het opslaan",
|
||||
"country" => "Land",
|
||||
"dashboard" => "",
|
||||
"dashboard" => "Dashboard",
|
||||
"date" => "Datum",
|
||||
"delete" => "Verwijderen",
|
||||
"det" => "details",
|
||||
@@ -26,14 +26,14 @@ return [
|
||||
"export_csv_no" => "Nee",
|
||||
"export_csv_yes" => "Ja",
|
||||
"fields_required_message" => "Rode velden zijn vereist",
|
||||
"fields_required_message_unique" => "",
|
||||
"fields_required_message_unique" => "Rode velden zijn vereist en moeten uniek zijn",
|
||||
"first_name" => "Voornaam",
|
||||
"first_name_required" => "Voornaam is een vereist veld.",
|
||||
"first_page" => "Eerste",
|
||||
"gender" => "Geslacht",
|
||||
"gender_female" => "V",
|
||||
"gender_male" => "M",
|
||||
"gender_undefined" => "",
|
||||
"gender_undefined" => "Ongedefinieerd",
|
||||
"icon" => "Pictogram",
|
||||
"id" => "ID",
|
||||
"import" => "Importeren",
|
||||
@@ -49,20 +49,20 @@ return [
|
||||
"learn_about_project" => "om de laatste informatie over het project te bekijken.",
|
||||
"list_of" => "Lijst van",
|
||||
"logo" => "Logo",
|
||||
"logo_mark" => "",
|
||||
"logo_mark" => "Merk",
|
||||
"logout" => "Afmelden",
|
||||
"manager" => "",
|
||||
"manager" => "Manager",
|
||||
"migration_needed" => "Een databasemigratie naar {0} zal starten na aanmelding.",
|
||||
"new" => "Nieuw",
|
||||
"no" => "",
|
||||
"no" => "Nee",
|
||||
"no_persons_to_display" => "Er zijn geen personen om te weergeven.",
|
||||
"none_selected_text" => "[Selecteren]",
|
||||
"or" => "OF",
|
||||
"people" => "",
|
||||
"people" => "Personen",
|
||||
"phone_number" => "Telefoonnummer",
|
||||
"phone_number_required" => "",
|
||||
"phone_number_required" => "Telefoonnummer is vereist",
|
||||
"please_visit_my" => "Bezoek de",
|
||||
"position" => "",
|
||||
"position" => "Positie",
|
||||
"powered_by" => "Mogelijk gemaakt door",
|
||||
"price" => "Prijs",
|
||||
"print" => "Afdrukken",
|
||||
@@ -73,8 +73,8 @@ return [
|
||||
"search" => "Zoeken",
|
||||
"search_options" => "Zoek opties",
|
||||
"searched_for" => "Gezocht naar",
|
||||
"software_short" => "",
|
||||
"software_title" => "",
|
||||
"software_short" => "OSPOS",
|
||||
"software_title" => "Open Source Point of Sale",
|
||||
"state" => "Provincie",
|
||||
"submit" => "Verzenden",
|
||||
"total_spent" => "Totaal uitgegeven",
|
||||
@@ -83,7 +83,7 @@ return [
|
||||
"website" => "opensourcepos.org",
|
||||
"welcome" => "Welkom",
|
||||
"welcome_message" => "Welkom bij OSPOS, klik op een module hieronder om te beginnen.",
|
||||
"yes" => "",
|
||||
"you_are_using_ospos" => "",
|
||||
"yes" => "Ja",
|
||||
"you_are_using_ospos" => "U gebruikt Open Source Point Of Sale Versie",
|
||||
"zip" => "Postcode",
|
||||
];
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
"administrator" => "",
|
||||
"administrator" => "Beheerder",
|
||||
"basic_information" => "Informatie",
|
||||
"cannot_be_deleted" => "Kan geselecteerde werknemer(s) niet verwijderen, één of meerdere bevatten verwerkte verkopen of u probeert uw account te verwijderen.",
|
||||
"change_employee" => "",
|
||||
"change_employee" => "Werknemer wijzigen",
|
||||
"change_password" => "Wachtwoord wijzigen",
|
||||
"clerk" => "",
|
||||
"commission" => "",
|
||||
"clerk" => "Bediende",
|
||||
"commission" => "Commissie",
|
||||
"confirm_delete" => "Weet u zeker dat u de geselecteerde werknemer(s) wilt verwijderen?",
|
||||
"confirm_restore" => "Weet u zeker dat u de geselecteerde werknemer(s) wilt herstellen?",
|
||||
"current_password" => "Huidige wachtwoord",
|
||||
"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_admin" => "U kunt een beheerder niet verwijderen.",
|
||||
"error_updating_admin" => "U kunt een beheerder niet wijzigen.",
|
||||
"error_deleting_demo_admin" => "Kan de demo admin gebruiker niet verwijderen.",
|
||||
"error_updating_demo_admin" => "Kan de demo admin gebruiker niet wijzigen.",
|
||||
"language" => "Taal",
|
||||
"login_info" => "Aanmelden",
|
||||
"manager" => "",
|
||||
"manager" => "Manager",
|
||||
"new" => "Nieuwe werknemer",
|
||||
"none_selected" => "Geen werknemer(s) geselecteerd om te verwijderen.",
|
||||
"one_or_multiple" => "werknemer(s)",
|
||||
|
||||
@@ -26,7 +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_invalid_location" => "Ongeldige voorraadlocatie(s) gevonden: {0}. Alleen geldige voorraadlocaties zijn toegestaan.",
|
||||
"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.",
|
||||
|
||||
@@ -146,4 +146,5 @@ return [
|
||||
"used" => "Punten gebruikt",
|
||||
"work_orders" => "Werkorders",
|
||||
"zero_and_less" => "Nul en minder",
|
||||
"toggle_cost_and_profit" => "Kosten en winst wisselen",
|
||||
];
|
||||
|
||||
@@ -222,4 +222,8 @@ return [
|
||||
"work_order_number_duplicate" => "Werkordernummer moet uniek zijn.",
|
||||
"work_order_sent" => "Werkorder verzonden naar",
|
||||
"work_order_unsent" => "Werkorder niet verzonden naar",
|
||||
"sale_not_found" => "Verkoop niet gevonden",
|
||||
"ubl_invoice" => "UBL-factuur",
|
||||
"download_ubl" => "UBL-factuur downloaden",
|
||||
"ubl_generation_failed" => "Genereren van UBL-factuur mislukt",
|
||||
];
|
||||
|
||||
@@ -5,6 +5,7 @@ return [
|
||||
"confirm_delete" => "Czy jesteś pewny, że chcesz usunąć wybrane atrybuty?",
|
||||
"confirm_restore" => "Czy jesteś pewien, że chcesz przywrócić zaznaczone atrybuty?",
|
||||
"definition_cannot_be_deleted" => "Nie można usunąć wybranych atrybutów",
|
||||
"definition_invalid_group" => "Wybrana grupa nie istnieje lub jest nieprawidłowa.",
|
||||
"definition_error_adding_updating" => "Atrybut 51 nie może zostać dodany lub zaktualizowany. Sprawdź dziennik błędów.",
|
||||
"definition_flags" => "Widoczność atrybutu",
|
||||
"definition_group" => "Grupa",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user