mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-05-30 03:07:56 -04:00
Compare commits
83 Commits
feature/re
...
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 | ||
|
|
9a2b308647 | ||
|
|
1f55d96580 | ||
|
|
b2fadea44a | ||
|
|
0fdb3ba37b | ||
|
|
d7b2264ac1 | ||
|
|
a229bf6031 | ||
|
|
977fa5647b | ||
|
|
52b0a83190 | ||
|
|
f25a0f5b09 | ||
|
|
f0f288797a | ||
|
|
63083a0946 | ||
|
|
3a33098776 | ||
|
|
ca6a1b35af | ||
|
|
418580a52d |
@@ -1,23 +1,56 @@
|
|||||||
node_modules
|
# Version control
|
||||||
tmp
|
.git
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Sensitive config (user may mount their own)
|
||||||
app/Config/Email.php
|
app/Config/Email.php
|
||||||
|
|
||||||
|
# Build artifacts
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
tmp/
|
||||||
*.patch
|
*.patch
|
||||||
patches/
|
patches/
|
||||||
|
|
||||||
|
# IDE and editor files
|
||||||
.idea/
|
.idea/
|
||||||
git-svn-diff.py
|
.vscode/
|
||||||
*.bash
|
|
||||||
.swp
|
.swp
|
||||||
|
*.swp
|
||||||
.buildpath
|
.buildpath
|
||||||
.project
|
.project
|
||||||
.settings/*
|
.settings/
|
||||||
.git
|
|
||||||
dist/
|
# Development tools and configs
|
||||||
node_modules/
|
tests/
|
||||||
*.swp
|
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
|
*.rej
|
||||||
*.orig
|
*.orig
|
||||||
*~
|
*~
|
||||||
*.~
|
*.~
|
||||||
*.log
|
*.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
|
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
|
# 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
|
|
||||||
14
.github/workflows/phpunit.yml
vendored
14
.github/workflows/phpunit.yml
vendored
@@ -69,9 +69,6 @@ jobs:
|
|||||||
- name: Install npm dependencies
|
- name: Install npm dependencies
|
||||||
run: npm install
|
run: npm install
|
||||||
|
|
||||||
- name: Build database.sql
|
|
||||||
run: npm run gulp build-database
|
|
||||||
|
|
||||||
- name: Start MariaDB
|
- name: Start MariaDB
|
||||||
run: |
|
run: |
|
||||||
docker run -d --name mysql \
|
docker run -d --name mysql \
|
||||||
@@ -79,7 +76,6 @@ jobs:
|
|||||||
-e MYSQL_DATABASE=ospos \
|
-e MYSQL_DATABASE=ospos \
|
||||||
-e MYSQL_USER=admin \
|
-e MYSQL_USER=admin \
|
||||||
-e MYSQL_PASSWORD=pointofsale \
|
-e MYSQL_PASSWORD=pointofsale \
|
||||||
-v $PWD/app/Database/database.sql:/docker-entrypoint-initdb.d/database.sql \
|
|
||||||
-p 3306:3306 \
|
-p 3306:3306 \
|
||||||
mariadb:10.5
|
mariadb:10.5
|
||||||
# Wait for MariaDB to be ready
|
# Wait for MariaDB to be ready
|
||||||
@@ -111,7 +107,15 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CI_ENVIRONMENT: testing
|
CI_ENVIRONMENT: testing
|
||||||
MYSQL_HOST_NAME: 127.0.0.1
|
MYSQL_HOST_NAME: 127.0.0.1
|
||||||
run: composer test
|
run: composer test -- --log-junit test-results/junit.xml
|
||||||
|
|
||||||
|
- name: Upload test results
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: test-results-php-${{ matrix.php-version }}
|
||||||
|
path: test-results/
|
||||||
|
retention-days: 30
|
||||||
|
|
||||||
- name: Stop MariaDB
|
- name: Stop MariaDB
|
||||||
if: always()
|
if: always()
|
||||||
|
|||||||
72
.github/workflows/update-issue-templates.yml
vendored
Normal file
72
.github/workflows/update-issue-templates.yml
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
name: Update Issue Templates
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * 0'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-templates:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Fetch releases and update templates
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
# Fetch releases from GitHub API
|
||||||
|
RELEASES=$(gh api repos/${{ github.repository }}/releases --jq '.[].tag_name' | head -n 10)
|
||||||
|
|
||||||
|
# Create temporary file with options
|
||||||
|
OPTIONS_FILE=$(mktemp)
|
||||||
|
echo " - development (unreleased)" >> "$OPTIONS_FILE"
|
||||||
|
while IFS= read -r release; do
|
||||||
|
echo " - opensourcepos $release" >> "$OPTIONS_FILE"
|
||||||
|
done <<< "$RELEASES"
|
||||||
|
|
||||||
|
update_template() {
|
||||||
|
local template="$1"
|
||||||
|
local template_path=".github/ISSUE_TEMPLATE/$template"
|
||||||
|
|
||||||
|
# Find the line numbers for the OpensourcePOS Version dropdown
|
||||||
|
start_line=$(grep -n "label: OpensourcePOS Version" "$template_path" | cut -d: -f1)
|
||||||
|
|
||||||
|
if [ -z "$start_line" ]; then
|
||||||
|
echo "Could not find OpensourcePOS Version in $template"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Find the options section and default line
|
||||||
|
options_start=$((start_line + 3))
|
||||||
|
default_line=$(grep -n "default:" "$template_path" | awk -F: -v opts="$options_start" '$1 > opts {print $1; exit}')
|
||||||
|
|
||||||
|
# Create new template file
|
||||||
|
head -n $((options_start - 1)) "$template_path" > "${template_path}.new"
|
||||||
|
cat "$OPTIONS_FILE" >> "${template_path}.new"
|
||||||
|
tail -n +$default_line "$template_path" >> "${template_path}.new"
|
||||||
|
mv "${template_path}.new" "$template_path"
|
||||||
|
|
||||||
|
echo "Updated $template"
|
||||||
|
}
|
||||||
|
|
||||||
|
update_template "bug report.yml"
|
||||||
|
update_template "feature_request.yml"
|
||||||
|
|
||||||
|
- name: Commit and push changes
|
||||||
|
run: |
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git add .github/ISSUE_TEMPLATE/*.yml
|
||||||
|
if git diff --staged --quiet; then
|
||||||
|
echo "No changes to commit"
|
||||||
|
else
|
||||||
|
git commit -m "Update issue templates with latest releases [skip ci]"
|
||||||
|
git push
|
||||||
|
fi
|
||||||
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
|
FROM php:8.2-apache AS ospos
|
||||||
LABEL maintainer="jekkos"
|
LABEL maintainer="jekkos"
|
||||||
|
|
||||||
RUN apt update && apt-get install -y libicu-dev libgd-dev
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
RUN a2enmod rewrite
|
libicu-dev \
|
||||||
RUN docker-php-ext-install mysqli bcmath intl gd
|
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
|
RUN echo "date.timezone = \"\${PHP_TIMEZONE}\"" > /usr/local/etc/php/conf.d/timezone.ini
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . /app
|
COPY --chown=www-data:www-data . /app
|
||||||
RUN ln -s /app/*[^public] /var/www && rm -rf /var/www/html && ln -nsf /app/public /var/www/html
|
RUN chmod 770 /app/writable/uploads /app/writable/logs /app/writable/cache \
|
||||||
RUN chmod -R 770 /app/writable/uploads /app/writable/logs /app/writable/cache && chown -R www-data:www-data /app
|
&& ln -s /app/*[^public] /var/www \
|
||||||
|
&& rm -rf /var/www/html \
|
||||||
FROM ospos AS ospos_test
|
&& ln -nsf /app/public /var/www/html
|
||||||
|
|
||||||
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"]
|
|
||||||
|
|
||||||
FROM ospos AS ospos_dev
|
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)>).
|
- 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.
|
- 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
|
## 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.
|
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.
|
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.
|
3. Unzip and upload Open Source Point of Sale files to the web-server.
|
||||||
4. 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` file and modify credentials to connect to your database if needed. (First copy .env.example to .env and update)
|
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.
|
7. Go to your install `public` dir via the browser.
|
||||||
8. Log in using
|
8. Log in using
|
||||||
- Username: admin
|
- Username: admin
|
||||||
- Password: pointofsale
|
- Password: pointofsale
|
||||||
9. If everything works, then set the `CI_ENVIRONMENT` variable to `production` in the .env file
|
9. If everything works, then set the `CI_ENVIRONMENT` variable to `production` in the .env file
|
||||||
9. Enjoy!
|
10. 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.
|
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
|
## Local install using Docker
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<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://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://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>
|
<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
|
## 🙏 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> |
|
| <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 [Travis CI](https://www.travis-ci.com/) for providing a free continuous integration service for open source projects. |
|
| 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 -->
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||||
|
|
||||||
|
|
||||||
- [Security Policy](#security-policy)
|
- [Security Policy](#security-policy)
|
||||||
- [Supported Versions](#supported-versions)
|
- [Supported Versions](#supported-versions)
|
||||||
|
- [Security Advisories](#security-advisories)
|
||||||
- [Reporting a Vulnerability](#reporting-a-vulnerability)
|
- [Reporting a Vulnerability](#reporting-a-vulnerability)
|
||||||
|
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
@@ -12,14 +12,35 @@
|
|||||||
|
|
||||||
## Supported Versions
|
## 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 |
|
| Version | Supported |
|
||||||
| --------- | -------------------------------------------------- |
|
| --------- | ------------------ |
|
||||||
| 7.3 | 3.3.5 |
|
| >= 3.4.2 | :white_check_mark: |
|
||||||
| 9.8 | 3.3.6 |
|
| < 3.4.2 | :x: |
|
||||||
| 6.8 | 3.4.2 |
|
|
||||||
|
## 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
|
## 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
|
public string $baseURL; // Defined in the constructor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allowed Hostnames in the Site URL other than the hostname in the baseURL.
|
* Allowed Hostnames for the Site URL.
|
||||||
* If you want to accept multiple Hostnames, set this.
|
*
|
||||||
*
|
* Security: This is used to validate the HTTP Host header to prevent
|
||||||
* E.g.,
|
* Host Header Injection attacks. If the Host header doesn't match
|
||||||
* When your site URL ($baseURL) is 'http://example.com/', and your site
|
* an entry in this list, the request will use the first allowed hostname.
|
||||||
* also accepts 'http://media.example.com/' and 'http://accounts.example.com/':
|
*
|
||||||
* ['media.example.com', 'accounts.example.com']
|
* 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>
|
* @var list<string>
|
||||||
*/
|
*/
|
||||||
@@ -284,8 +292,44 @@ class App extends BaseConfig
|
|||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->https_on = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_ENV['FORCE_HTTPS']) && $_ENV['FORCE_HTTPS'] == 'true');
|
$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 = $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']);
|
$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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,3 +169,8 @@ const MAX_PRECISION = 1e14;
|
|||||||
const DEFAULT_PRECISION = 2;
|
const DEFAULT_PRECISION = 2;
|
||||||
const DEFAULT_LANGUAGE = 'english';
|
const DEFAULT_LANGUAGE = 'english';
|
||||||
const DEFAULT_LANGUAGE_CODE = 'en';
|
const DEFAULT_LANGUAGE_CODE = 'en';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Admin modules - list of modules required for admin privileges
|
||||||
|
*/
|
||||||
|
const ADMIN_MODULES = ['customers', 'employees', 'giftcards', 'items', 'item_kits', 'messages', 'receivings', 'reports', 'sales', 'config', 'suppliers'];
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ $routes->get('/', 'Login::index');
|
|||||||
$routes->get('login', 'Login::index');
|
$routes->get('login', 'Login::index');
|
||||||
$routes->post('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)', 'No_access::index/$1');
|
||||||
$routes->add('no_access/index/(:segment)/(:segment)', 'No_access::index/$1/$2');
|
$routes->add('no_access/index/(:segment)/(:segment)', 'No_access::index/$1/$2');
|
||||||
|
|
||||||
|
|||||||
@@ -106,12 +106,24 @@ class Attributes extends Secure_Controller
|
|||||||
$definition_flags |= $flag;
|
$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
|
// Save definition data
|
||||||
$definition_data = [
|
$definition_data = [
|
||||||
'definition_name' => $this->request->getPost('definition_name'),
|
'definition_name' => $this->request->getPost('definition_name'),
|
||||||
'definition_unit' => $this->request->getPost('definition_unit') != '' ? $this->request->getPost('definition_unit') : null,
|
'definition_unit' => $this->request->getPost('definition_unit') != '' ? $this->request->getPost('definition_unit') : null,
|
||||||
'definition_flags' => $definition_flags,
|
'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) {
|
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
|
* @param int $definition_id
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ class Cashups extends Secure_Controller
|
|||||||
// filters that will be loaded in the multiselect dropdown
|
// filters that will be loaded in the multiselect dropdown
|
||||||
$data['filters'] = ['is_deleted' => lang('Cashups.is_deleted')];
|
$data['filters'] = ['is_deleted' => lang('Cashups.is_deleted')];
|
||||||
|
|
||||||
|
// Restore filters from URL
|
||||||
|
$data = array_merge($data, restoreTableFilters($this->request));
|
||||||
|
|
||||||
return view('cashups/manage', $data);
|
return view('cashups/manage', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use App\Models\Appconfig;
|
|||||||
use App\Models\Attribute;
|
use App\Models\Attribute;
|
||||||
use App\Models\Customer_rewards;
|
use App\Models\Customer_rewards;
|
||||||
use App\Models\Dinner_table;
|
use App\Models\Dinner_table;
|
||||||
|
use App\Models\Item;
|
||||||
use App\Models\Module;
|
use App\Models\Module;
|
||||||
use App\Models\Enums\Rounding_mode;
|
use App\Models\Enums\Rounding_mode;
|
||||||
use App\Models\Stock_location;
|
use App\Models\Stock_location;
|
||||||
@@ -385,9 +386,9 @@ class Config extends Secure_Controller
|
|||||||
'gcaptcha_enable' => $this->request->getPost('gcaptcha_enable') != null,
|
'gcaptcha_enable' => $this->request->getPost('gcaptcha_enable') != null,
|
||||||
'gcaptcha_secret_key' => $this->request->getPost('gcaptcha_secret_key'),
|
'gcaptcha_secret_key' => $this->request->getPost('gcaptcha_secret_key'),
|
||||||
'gcaptcha_site_key' => $this->request->getPost('gcaptcha_site_key'),
|
'gcaptcha_site_key' => $this->request->getPost('gcaptcha_site_key'),
|
||||||
'suggestions_first_column' => $this->request->getPost('suggestions_first_column'),
|
'suggestions_first_column' => $this->validateSuggestionsColumn($this->request->getPost('suggestions_first_column'), 'first'),
|
||||||
'suggestions_second_column' => $this->request->getPost('suggestions_second_column'),
|
'suggestions_second_column' => $this->validateSuggestionsColumn($this->request->getPost('suggestions_second_column'), 'other'),
|
||||||
'suggestions_third_column' => $this->request->getPost('suggestions_third_column'),
|
'suggestions_third_column' => $this->validateSuggestionsColumn($this->request->getPost('suggestions_third_column'), 'other'),
|
||||||
'giftcard_number' => $this->request->getPost('giftcard_number'),
|
'giftcard_number' => $this->request->getPost('giftcard_number'),
|
||||||
'derive_sale_quantity' => $this->request->getPost('derive_sale_quantity') != null,
|
'derive_sale_quantity' => $this->request->getPost('derive_sale_quantity') != null,
|
||||||
'multi_pack_enabled' => $this->request->getPost('multi_pack_enabled') != null,
|
'multi_pack_enabled' => $this->request->getPost('multi_pack_enabled') != null,
|
||||||
@@ -461,8 +462,9 @@ class Config extends Secure_Controller
|
|||||||
public function postSaveLocale(): ResponseInterface
|
public function postSaveLocale(): ResponseInterface
|
||||||
{
|
{
|
||||||
$exploded = explode(":", $this->request->getPost('language'));
|
$exploded = explode(":", $this->request->getPost('language'));
|
||||||
|
$currency_symbol = $this->request->getPost('currency_symbol');
|
||||||
$batch_save_data = [
|
$batch_save_data = [
|
||||||
'currency_symbol' => $this->request->getPost('currency_symbol'),
|
'currency_symbol' => htmlspecialchars($currency_symbol ?? ''),
|
||||||
'currency_code' => $this->request->getPost('currency_code'),
|
'currency_code' => $this->request->getPost('currency_code'),
|
||||||
'language_code' => $exploded[0],
|
'language_code' => $exploded[0],
|
||||||
'language' => $exploded[1],
|
'language' => $exploded[1],
|
||||||
@@ -975,4 +977,26 @@ class Config extends Secure_Controller
|
|||||||
|
|
||||||
return $this->response->setJSON(['success' => $success]);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class Employees extends Persons
|
|||||||
$person_info = $this->employee->get_info($employee_id);
|
$person_info = $this->employee->get_info($employee_id);
|
||||||
$current_user = $this->employee->get_logged_in_employee_info();
|
$current_user = $this->employee->get_logged_in_employee_info();
|
||||||
|
|
||||||
if ($employee_id != NEW_ENTRY && !$this->employee->can_modify_employee($person_info->person_id, $current_user->person_id)) {
|
if ($employee_id != NEW_ENTRY && !$this->employee->canModifyEmployee($person_info->person_id, $current_user->person_id)) {
|
||||||
header('Location: ' . base_url('no_access/employees/employees'));
|
header('Location: ' . base_url('no_access/employees/employees'));
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ class Employees extends Persons
|
|||||||
|
|
||||||
if ($employee_id != NEW_ENTRY) {
|
if ($employee_id != NEW_ENTRY) {
|
||||||
$target_employee = $this->employee->get_info($employee_id);
|
$target_employee = $this->employee->get_info($employee_id);
|
||||||
if (!$this->employee->can_modify_employee($target_employee->person_id, $current_user->person_id)) {
|
if (!$this->employee->canModifyEmployee($target_employee->person_id, $current_user->person_id)) {
|
||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
'message' => lang('Employees.error_updating_admin'),
|
'message' => lang('Employees.error_updating_admin'),
|
||||||
@@ -153,14 +153,14 @@ class Employees extends Persons
|
|||||||
];
|
];
|
||||||
|
|
||||||
$grants_array = [];
|
$grants_array = [];
|
||||||
$is_admin = $this->employee->is_admin($current_user->person_id);
|
$isAdmin = $this->employee->isAdmin($current_user->person_id);
|
||||||
|
|
||||||
foreach ($this->module->get_all_permissions()->getResult() as $permission) {
|
foreach ($this->module->get_all_permissions()->getResult() as $permission) {
|
||||||
$grants = [];
|
$grants = [];
|
||||||
$grant = $this->request->getPost('grant_' . $permission->permission_id) != null ? $this->request->getPost('grant_' . $permission->permission_id, FILTER_SANITIZE_FULL_SPECIAL_CHARS) : '';
|
$grant = $this->request->getPost('grant_' . $permission->permission_id) != null ? $this->request->getPost('grant_' . $permission->permission_id, FILTER_SANITIZE_FULL_SPECIAL_CHARS) : '';
|
||||||
|
|
||||||
if ($grant == $permission->permission_id) {
|
if ($grant == $permission->permission_id) {
|
||||||
if (!$is_admin && !$this->employee->has_grant($permission->permission_id, $current_user->person_id)) {
|
if (!$isAdmin && !$this->employee->has_grant($permission->permission_id, $current_user->person_id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$grants['permission_id'] = $permission->permission_id;
|
$grants['permission_id'] = $permission->permission_id;
|
||||||
@@ -226,9 +226,9 @@ class Employees extends Persons
|
|||||||
$employees_to_delete = $this->request->getPost('ids', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
$employees_to_delete = $this->request->getPost('ids', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||||
$current_user = $this->employee->get_logged_in_employee_info();
|
$current_user = $this->employee->get_logged_in_employee_info();
|
||||||
|
|
||||||
if (!$this->employee->is_admin($current_user->person_id)) {
|
if (!$this->employee->isAdmin($current_user->person_id)) {
|
||||||
foreach ($employees_to_delete as $emp_id) {
|
foreach ($employees_to_delete as $emp_id) {
|
||||||
if ($this->employee->is_admin((int)$emp_id)) {
|
if ($this->employee->isAdmin((int)$emp_id)) {
|
||||||
return $this->response->setJSON(['success' => false, 'message' => lang('Employees.error_deleting_admin')]);
|
return $this->response->setJSON(['success' => false, 'message' => lang('Employees.error_deleting_admin')]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ class Expenses extends Secure_Controller
|
|||||||
'is_deleted' => lang('Expenses.is_deleted')
|
'is_deleted' => lang('Expenses.is_deleted')
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Restore filters from URL
|
||||||
|
$data = array_merge($data, restoreTableFilters($this->request));
|
||||||
|
|
||||||
return view('expenses/manage', $data);
|
return view('expenses/manage', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,16 +93,23 @@ class Expenses extends Secure_Controller
|
|||||||
{
|
{
|
||||||
$data = []; // TODO: Duplicated code
|
$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);
|
$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 = [];
|
$expense_categories = [];
|
||||||
foreach ($this->expense_category->get_all(0, 0, true)->getResultArray() as $row) {
|
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;
|
$data['expense_categories'] = $expense_categories;
|
||||||
|
|
||||||
$expense_id = $data['expenses_info']->expense_id;
|
|
||||||
|
|
||||||
if ($expense_id == NEW_ENTRY) {
|
if ($expense_id == NEW_ENTRY) {
|
||||||
$data['expenses_info']->date = date('Y-m-d H:i:s');
|
$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'] = [];
|
$data['payments'] = [];
|
||||||
@@ -152,6 +160,20 @@ class Expenses extends Secure_Controller
|
|||||||
|
|
||||||
$date_formatter = date_create_from_format($config['dateformat'] . ' ' . $config['timeformat'], $newdate);
|
$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 = [
|
$expense_data = [
|
||||||
'date' => $date_formatter->format('Y-m-d H:i:s'),
|
'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),
|
'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),
|
'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),
|
'expense_category_id' => $this->request->getPost('expense_category_id', FILTER_SANITIZE_NUMBER_INT),
|
||||||
'description' => $this->request->getPost('description', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
|
'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
|
'deleted' => $this->request->getPost('deleted') != null
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -36,12 +36,21 @@ class Home extends Secure_Controller
|
|||||||
/**
|
/**
|
||||||
* Load "change employee password" form
|
* Load "change employee password" form
|
||||||
*
|
*
|
||||||
* @return string
|
* @return ResponseInterface|string
|
||||||
* @noinspection PhpUnused
|
* @noinspection PhpUnused
|
||||||
*/
|
*/
|
||||||
public function getChangePassword(int $employee_id = -1): string // TODO: Replace -1 with a constant
|
public function getChangePassword(int $employeeId = NEW_ENTRY)
|
||||||
{
|
{
|
||||||
$person_info = $this->employee->get_info($employee_id);
|
$loggedInEmployee = $this->employee->get_logged_in_employee_info();
|
||||||
|
$currentPersonId = $loggedInEmployee->person_id;
|
||||||
|
|
||||||
|
$employeeId = $employeeId === NEW_ENTRY ? $currentPersonId : $employeeId;
|
||||||
|
|
||||||
|
if (!$this->employee->isAdmin($currentPersonId) && $employeeId !== $currentPersonId) {
|
||||||
|
return $this->response->setStatusCode(403)->setBody(lang('Employees.unauthorized_modify'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$person_info = $this->employee->get_info($employeeId);
|
||||||
foreach (get_object_vars($person_info) as $property => $value) {
|
foreach (get_object_vars($person_info) as $property => $value) {
|
||||||
$person_info->$property = $value;
|
$person_info->$property = $value;
|
||||||
}
|
}
|
||||||
@@ -55,9 +64,20 @@ class Home extends Secure_Controller
|
|||||||
*
|
*
|
||||||
* @return ResponseInterface
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
public function postSave(int $employee_id = -1): ResponseInterface // TODO: Replace -1 with a constant
|
public function postSave(int $employeeId = NEW_ENTRY): ResponseInterface
|
||||||
{
|
{
|
||||||
if (!empty($this->request->getPost('current_password')) && $employee_id != -1) {
|
$currentUser = $this->employee->get_logged_in_employee_info();
|
||||||
|
|
||||||
|
$employeeId = $employeeId === NEW_ENTRY ? $currentUser->person_id : $employeeId;
|
||||||
|
|
||||||
|
if (!$this->employee->isAdmin($currentUser->person_id) && $employeeId !== $currentUser->person_id) {
|
||||||
|
return $this->response->setStatusCode(403)->setJSON([
|
||||||
|
'success' => false,
|
||||||
|
'message' => lang('Employees.unauthorized_modify')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->request->getPost('current_password')) && $employeeId != NEW_ENTRY) {
|
||||||
if ($this->employee->check_password($this->request->getPost('username', FILTER_SANITIZE_FULL_SPECIAL_CHARS), $this->request->getPost('current_password'))) {
|
if ($this->employee->check_password($this->request->getPost('username', FILTER_SANITIZE_FULL_SPECIAL_CHARS), $this->request->getPost('current_password'))) {
|
||||||
// Validate password length BEFORE hashing
|
// Validate password length BEFORE hashing
|
||||||
$new_password = $this->request->getPost('password');
|
$new_password = $this->request->getPost('password');
|
||||||
@@ -66,7 +86,7 @@ class Home extends Secure_Controller
|
|||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
'message' => lang('Employees.password_minlength'),
|
'message' => lang('Employees.password_minlength'),
|
||||||
'id' => -1
|
'id' => NEW_ENTRY
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,32 +96,32 @@ class Home extends Secure_Controller
|
|||||||
'hash_version' => 2
|
'hash_version' => 2
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($this->employee->change_password($employee_data, $employee_id)) {
|
if ($this->employee->change_password($employee_data, $employeeId)) {
|
||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'message' => lang('Employees.successful_change_password'),
|
'message' => lang('Employees.successful_change_password'),
|
||||||
'id' => $employee_id
|
'id' => $employeeId
|
||||||
]);
|
]);
|
||||||
} else { // Failure // TODO: Replace -1 with constant
|
} else {
|
||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
'message' => lang('Employees.unsuccessful_change_password'),
|
'message' => lang('Employees.unsuccessful_change_password'),
|
||||||
'id' => -1
|
'id' => NEW_ENTRY
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} else { // TODO: Replace -1 with constant
|
} else {
|
||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
'message' => lang('Employees.current_password_invalid'),
|
'message' => lang('Employees.current_password_invalid'),
|
||||||
'id' => -1
|
'id' => NEW_ENTRY
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} else { // TODO: Replace -1 with constant
|
} else {
|
||||||
return $this->response->setJSON([
|
return $this->response->setJSON([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
'message' => lang('Employees.current_password_invalid'),
|
'message' => lang('Employees.current_password_invalid'),
|
||||||
'id' => -1
|
'id' => NEW_ENTRY
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,12 @@ class Items extends Secure_Controller
|
|||||||
$this->session->set('allow_temp_items', 0);
|
$this->session->set('allow_temp_items', 0);
|
||||||
|
|
||||||
$data['table_headers'] = get_items_manage_table_headers();
|
$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();
|
$data['stock_locations'] = $this->stock_location->get_allowed_locations();
|
||||||
|
|
||||||
// Filters that will be loaded in the multiselect dropdown
|
// Filters that will be loaded in the multiselect dropdown
|
||||||
@@ -87,6 +92,9 @@ class Items extends Secure_Controller
|
|||||||
'temporary' => lang('Items.temp')
|
'temporary' => lang('Items.temp')
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Restore filters from URL
|
||||||
|
$data = array_merge($data, restoreTableFilters($this->request));
|
||||||
|
|
||||||
return view('items/manage', $data);
|
return view('items/manage', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +104,7 @@ class Items extends Secure_Controller
|
|||||||
**/
|
**/
|
||||||
public function getSearch(): ResponseInterface
|
public function getSearch(): ResponseInterface
|
||||||
{
|
{
|
||||||
$search = $this->request->getGet('search');
|
$search = $this->request->getGet('search', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||||
$limit = $this->request->getGet('limit', FILTER_SANITIZE_NUMBER_INT);
|
$limit = $this->request->getGet('limit', FILTER_SANITIZE_NUMBER_INT);
|
||||||
$offset = $this->request->getGet('offset', FILTER_SANITIZE_NUMBER_INT);
|
$offset = $this->request->getGet('offset', FILTER_SANITIZE_NUMBER_INT);
|
||||||
$sort = $this->sanitizeSortColumn(item_headers(), $this->request->getGet('sort', FILTER_SANITIZE_FULL_SPECIAL_CHARS), 'item_id');
|
$sort = $this->sanitizeSortColumn(item_headers(), $this->request->getGet('sort', FILTER_SANITIZE_FULL_SPECIAL_CHARS), 'item_id');
|
||||||
@@ -148,6 +156,7 @@ class Items extends Secure_Controller
|
|||||||
{
|
{
|
||||||
helper('file');
|
helper('file');
|
||||||
|
|
||||||
|
$pic_filename = rawurldecode($pic_filename);
|
||||||
$file_extension = pathinfo($pic_filename, PATHINFO_EXTENSION);
|
$file_extension = pathinfo($pic_filename, PATHINFO_EXTENSION);
|
||||||
$images = glob("./uploads/item_pics/$pic_filename");
|
$images = glob("./uploads/item_pics/$pic_filename");
|
||||||
$base_path = './uploads/item_pics/' . pathinfo($pic_filename, PATHINFO_FILENAME);
|
$base_path = './uploads/item_pics/' . pathinfo($pic_filename, PATHINFO_FILENAME);
|
||||||
@@ -377,7 +386,7 @@ class Items extends Secure_Controller
|
|||||||
} else {
|
} else {
|
||||||
$images = glob("./uploads/item_pics/$item_info->pic_filename");
|
$images = glob("./uploads/item_pics/$item_info->pic_filename");
|
||||||
}
|
}
|
||||||
$data['image_path'] = sizeof($images) > 0 ? base_url($images[0]) : '';
|
$data['image_path'] = sizeof($images) > 0 ? base_url(implode('/', array_map('rawurlencode', explode('/', ltrim($images[0], './'))))) : '';
|
||||||
} else {
|
} else {
|
||||||
$data['image_path'] = '';
|
$data['image_path'] = '';
|
||||||
}
|
}
|
||||||
@@ -617,7 +626,7 @@ class Items extends Secure_Controller
|
|||||||
// Save item data
|
// Save item data
|
||||||
$item_data = [
|
$item_data = [
|
||||||
'name' => $this->request->getPost('name'),
|
'name' => $this->request->getPost('name'),
|
||||||
'description' => $this->request->getPost('description'),
|
'description' => $this->request->getPost('description', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
|
||||||
'category' => $this->request->getPost('category'),
|
'category' => $this->request->getPost('category'),
|
||||||
'item_type' => $item_type,
|
'item_type' => $item_type,
|
||||||
'stock_type' => $this->request->getPost('stock_type') === null ? HAS_STOCK : intval($this->request->getPost('stock_type')),
|
'stock_type' => $this->request->getPost('stock_type') === null ? HAS_STOCK : intval($this->request->getPost('stock_type')),
|
||||||
@@ -768,10 +777,13 @@ class Items extends Secure_Controller
|
|||||||
|
|
||||||
$filename = $file->getClientName();
|
$filename = $file->getClientName();
|
||||||
$info = pathinfo($filename);
|
$info = pathinfo($filename);
|
||||||
|
|
||||||
|
// Sanitize filename to remove problematic characters like spaces
|
||||||
|
$sanitized_name = preg_replace('/[^a-zA-Z0-9_\-\.]/', '_', $info['filename']);
|
||||||
|
|
||||||
$file_info = [
|
$file_info = [
|
||||||
'orig_name' => $filename,
|
'orig_name' => $filename,
|
||||||
'raw_name' => $info['filename'],
|
'raw_name' => $sanitized_name,
|
||||||
'file_ext' => $file->guessExtension()
|
'file_ext' => $file->guessExtension()
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -872,12 +884,12 @@ class Items extends Secure_Controller
|
|||||||
$items_to_update = $this->request->getPost('item_ids');
|
$items_to_update = $this->request->getPost('item_ids');
|
||||||
$item_data = [];
|
$item_data = [];
|
||||||
|
|
||||||
foreach ($_POST as $key => $value) {
|
foreach (Item::ALLOWED_BULK_EDIT_FIELDS as $field) {
|
||||||
// This field is nullable, so treat it differently
|
$value = $this->request->getPost($field);
|
||||||
if ($key === 'supplier_id' && $value !== '') {
|
if ($field === 'supplier_id' && $value !== '') {
|
||||||
$item_data[$key] = $value;
|
$item_data[$field] = $value;
|
||||||
} elseif ($value !== '' && !(in_array($key, ['item_ids', 'tax_names', 'tax_percents']))) {
|
} elseif ($value !== null && $value !== '') {
|
||||||
$item_data[$key] = $value;
|
$item_data[$field] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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;
|
$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'] = [];
|
$data['employees'] = [];
|
||||||
foreach ($this->employee->get_all()->getResult() as $employee) {
|
if ($can_assign_employee) {
|
||||||
$data['employees'][$employee->person_id] = $employee->first_name . ' ' . $employee->last_name;
|
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_name'] = !empty($receiving_info['supplier_id']) ? $receiving_info['company_name'] : '';
|
||||||
$data['selected_supplier_id'] = $receiving_info['supplier_id'];
|
$data['selected_supplier_id'] = $receiving_info['supplier_id'];
|
||||||
$data['receiving_info'] = $receiving_info;
|
$data['receiving_info'] = $receiving_info;
|
||||||
|
$data['can_assign_employee'] = $can_assign_employee;
|
||||||
|
|
||||||
return view('receivings/form', $data);
|
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);
|
$date_formatter = date_create_from_format($this->config['dateformat'] . ' ' . $this->config['timeformat'], $newdate);
|
||||||
$receiving_time = $date_formatter->format('Y-m-d H:i:s');
|
$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_data = [
|
||||||
'receiving_time' => $receiving_time,
|
'receiving_time' => $receiving_time,
|
||||||
'supplier_id' => $this->request->getPost('supplier_id') ? $this->request->getPost('supplier_id', FILTER_SANITIZE_NUMBER_INT) : null,
|
'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),
|
'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
|
'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();
|
$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 = [
|
$inputs = [
|
||||||
'start_date' => $start_date,
|
'start_date' => $start_date,
|
||||||
@@ -1789,7 +1789,12 @@ class Reports extends Secure_Controller
|
|||||||
$this->detailed_sales->create($inputs);
|
$this->detailed_sales->create($inputs);
|
||||||
|
|
||||||
$columns = $this->detailed_sales->getDataColumns();
|
$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;
|
$headers = $columns;
|
||||||
|
|
||||||
@@ -1930,14 +1935,19 @@ class Reports extends Secure_Controller
|
|||||||
{
|
{
|
||||||
$this->clearCache();
|
$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)];
|
$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);
|
$this->detailed_receivings->create($inputs);
|
||||||
|
|
||||||
$columns = $this->detailed_receivings->getDataColumns();
|
$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;
|
$headers = $columns;
|
||||||
$report_data = $this->detailed_receivings->getData($inputs);
|
$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_invoice_count;
|
||||||
use App\Models\Tokens\Token_customer;
|
use App\Models\Tokens\Token_customer;
|
||||||
use App\Models\Tokens\Token_invoice_sequence;
|
use App\Models\Tokens\Token_invoice_sequence;
|
||||||
|
use CodeIgniter\Events\Events;
|
||||||
use CodeIgniter\HTTP\ResponseInterface;
|
use CodeIgniter\HTTP\ResponseInterface;
|
||||||
use Config\Services;
|
use Config\Services;
|
||||||
use Config\OSPOS;
|
use Config\OSPOS;
|
||||||
@@ -75,15 +76,15 @@ class Sales extends Secure_Controller
|
|||||||
/**
|
/**
|
||||||
* Load the sale edit modal. Used in app/Views/sales/register.php.
|
* Load the sale edit modal. Used in app/Views/sales/register.php.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return ResponseInterface|string
|
||||||
* @noinspection PhpUnused
|
* @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)) {
|
if (!$this->employee->has_grant('reports_sales', $personId)) {
|
||||||
redirect('no_access/sales/reports_sales');
|
return redirect()->to('no_access/sales/reports_sales');
|
||||||
} else {
|
} else {
|
||||||
$data['table_headers'] = get_sales_manage_table_headers();
|
$data['table_headers'] = get_sales_manage_table_headers();
|
||||||
|
|
||||||
@@ -92,18 +93,31 @@ class Sales extends Secure_Controller
|
|||||||
'only_due' => lang('Sales.due_filter'),
|
'only_due' => lang('Sales.due_filter'),
|
||||||
'only_check' => lang('Sales.check_filter'),
|
'only_check' => lang('Sales.check_filter'),
|
||||||
'only_creditcard' => lang('Sales.credit_filter'),
|
'only_creditcard' => lang('Sales.credit_filter'),
|
||||||
|
'only_debit' => lang('Sales.debit'),
|
||||||
'only_invoices' => lang('Sales.invoice_filter'),
|
'only_invoices' => lang('Sales.invoice_filter'),
|
||||||
'selected_customer' => lang('Sales.selected_customer')
|
'selected_customer' => lang('Sales.selected_customer')
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($this->sale_lib->get_customer() != -1) {
|
if ($this->sale_lib->get_customer() != -1) {
|
||||||
$selected_filters = ['selected_customer'];
|
$selectedFilters = ['selected_customer'];
|
||||||
$data['customer_selected'] = true;
|
$data['customer_selected'] = true;
|
||||||
} else {
|
} else {
|
||||||
$data['customer_selected'] = false;
|
$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);
|
return view('sales/manage', $data);
|
||||||
}
|
}
|
||||||
@@ -142,6 +156,7 @@ class Sales extends Secure_Controller
|
|||||||
'only_check' => false,
|
'only_check' => false,
|
||||||
'selected_customer' => false,
|
'selected_customer' => false,
|
||||||
'only_creditcard' => false,
|
'only_creditcard' => false,
|
||||||
|
'only_debit' => false,
|
||||||
'only_invoices' => $this->config['invoice_enable'] && $this->request->getGet('only_invoices', FILTER_SANITIZE_NUMBER_INT),
|
'only_invoices' => $this->config['invoice_enable'] && $this->request->getGet('only_invoices', FILTER_SANITIZE_NUMBER_INT),
|
||||||
'is_valid_receipt' => $this->sale->is_valid_receipt($search)
|
'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);
|
return $this->_reload($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -772,8 +794,18 @@ class Sales extends Secure_Controller
|
|||||||
$data['error_message'] = lang('Sales.transaction_failed');
|
$data['error_message'] = lang('Sales.transaction_failed');
|
||||||
} else {
|
} else {
|
||||||
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']);
|
$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();
|
$this->sale_lib->clear_all();
|
||||||
|
return view('sales/' . $invoice_view, $data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($this->sale_lib->is_work_order_mode()) {
|
} elseif ($this->sale_lib->is_work_order_mode()) {
|
||||||
@@ -806,9 +838,8 @@ class Sales extends Secure_Controller
|
|||||||
|
|
||||||
$data['barcode'] = null;
|
$data['barcode'] = null;
|
||||||
|
|
||||||
return view('sales/work_order', $data);
|
|
||||||
$this->sale_lib->clear_mode();
|
|
||||||
$this->sale_lib->clear_all();
|
$this->sale_lib->clear_all();
|
||||||
|
return view('sales/work_order', $data);
|
||||||
}
|
}
|
||||||
} elseif ($this->sale_lib->is_quote_mode()) {
|
} elseif ($this->sale_lib->is_quote_mode()) {
|
||||||
$data['sales_quote'] = lang('Sales.quote');
|
$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['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']);
|
||||||
$data['barcode'] = null;
|
$data['barcode'] = null;
|
||||||
|
|
||||||
return view('sales/quote', $data);
|
|
||||||
$this->sale_lib->clear_mode();
|
|
||||||
$this->sale_lib->clear_all();
|
$this->sale_lib->clear_all();
|
||||||
|
return view('sales/quote', $data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Save the data to the sales table
|
// Save the data to the sales table
|
||||||
@@ -857,8 +887,18 @@ class Sales extends Secure_Controller
|
|||||||
$data['error_message'] = lang('Sales.transaction_failed');
|
$data['error_message'] = lang('Sales.transaction_failed');
|
||||||
} else {
|
} else {
|
||||||
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']);
|
$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();
|
$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,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migration to sanitize existing image filenames by replacing spaces with underscores
|
||||||
|
* This fixes issue #4372 where thumbnails failed to load for images with spaces in filenames
|
||||||
|
*/
|
||||||
|
class FixImageFilenameSpaces extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Perform a migration.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
$db = \Config\Database::connect();
|
||||||
|
$builder = $db->table('ospos_items');
|
||||||
|
|
||||||
|
// Get all items with pic_filename containing spaces
|
||||||
|
$query = $builder->like('pic_filename', ' ', 'both')->get();
|
||||||
|
$items = $query->getResult();
|
||||||
|
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$old_filename = $item->pic_filename;
|
||||||
|
$ext = pathinfo($old_filename, PATHINFO_EXTENSION);
|
||||||
|
$base_name = pathinfo($old_filename, PATHINFO_FILENAME);
|
||||||
|
|
||||||
|
// Sanitize the filename by replacing spaces and special characters
|
||||||
|
$sanitized_name = preg_replace('/[^a-zA-Z0-9_\-\.]/', '_', $base_name);
|
||||||
|
$new_filename = $sanitized_name . '.' . $ext;
|
||||||
|
|
||||||
|
// Rename the file on the filesystem
|
||||||
|
$old_path = FCPATH . 'uploads/item_pics/' . $old_filename;
|
||||||
|
$new_path = FCPATH . 'uploads/item_pics/' . $new_filename;
|
||||||
|
|
||||||
|
if (file_exists($old_path)) {
|
||||||
|
// Rename the original file
|
||||||
|
if (rename($old_path, $new_path)) {
|
||||||
|
// Check if thumbnail exists and rename it too
|
||||||
|
$old_thumb = FCPATH . 'uploads/item_pics/' . $base_name . '_thumb.' . $ext;
|
||||||
|
$new_thumb = FCPATH . 'uploads/item_pics/' . $sanitized_name . '_thumb.' . $ext;
|
||||||
|
if (file_exists($old_thumb)) {
|
||||||
|
rename($old_thumb, $new_thumb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update database record
|
||||||
|
$builder->where('item_id', $item->item_id)
|
||||||
|
->update(['pic_filename' => $new_filename]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revert a migration.
|
||||||
|
* Note: This migration does not support rollback as the original filenames are lost
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
// This migration cannot be safely reversed as the original filenames are lost
|
||||||
|
// after sanitization.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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`
|
-- 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
|
<?php
|
||||||
|
|
||||||
use App\Models\Employee;
|
use App\Models\Employee;
|
||||||
|
use CodeIgniter\Events\Events;
|
||||||
use Config\OSPOS;
|
use Config\OSPOS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -276,6 +277,12 @@ function get_payment_options(): array
|
|||||||
$payments[lang('Sales.upi')] = lang('Sales.upi');
|
$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;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,7 +48,7 @@ function transform_headers(array $headers, bool $readonly = false, bool $editabl
|
|||||||
'field' => key($element),
|
'field' => key($element),
|
||||||
'title' => current($element),
|
'title' => current($element),
|
||||||
'switchable' => $element['switchable'] ?? !preg_match('(^$| )', current($element)),
|
'switchable' => $element['switchable'] ?? !preg_match('(^$| )', current($element)),
|
||||||
'escape' => !preg_match("/(edit|email|messages|item_pic|customer_name|note)/", key($element)) && !(isset($element['escape']) && !$element['escape']),
|
'escape' => !preg_match("/(edit|email|messages|item_pic)/", key($element)) && !(isset($element['escape']) && !$element['escape']),
|
||||||
'sortable' => $element['sortable'] ?? current($element) != '',
|
'sortable' => $element['sortable'] ?? current($element) != '',
|
||||||
'checkbox' => $element['checkbox'] ?? false,
|
'checkbox' => $element['checkbox'] ?? false,
|
||||||
'class' => isset($element['checkbox']) || preg_match('(^$| )', current($element)) ? 'print_hide' : '',
|
'class' => isset($element['checkbox']) || preg_match('(^$| )', current($element)) ? 'print_hide' : '',
|
||||||
@@ -408,7 +408,7 @@ function get_items_manage_table_headers(): string
|
|||||||
{
|
{
|
||||||
$attribute = model(Attribute::class);
|
$attribute = model(Attribute::class);
|
||||||
$config = config(OSPOS::class)->settings;
|
$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();
|
$headers = item_headers();
|
||||||
|
|
||||||
@@ -420,8 +420,8 @@ function get_items_manage_table_headers(): string
|
|||||||
|
|
||||||
$headers[] = ['item_pic' => lang('Items.image'), 'sortable' => false];
|
$headers[] = ['item_pic' => lang('Items.image'), 'sortable' => false];
|
||||||
|
|
||||||
foreach ($definition_names as $definition_id => $definition_name) {
|
foreach ($definitionsWithTypes as $definition_id => $definitionInfo) {
|
||||||
$headers[] = [$definition_id => $definition_name, 'sortable' => false];
|
$headers[] = [$definition_id => $definitionInfo['name'], 'sortable' => false];
|
||||||
}
|
}
|
||||||
|
|
||||||
$headers[] = ['inventory' => '', 'escape' => false];
|
$headers[] = ['inventory' => '', 'escape' => false];
|
||||||
@@ -470,7 +470,8 @@ function get_item_data_row(object $item): array
|
|||||||
: glob("./uploads/item_pics/$item->pic_filename");
|
: glob("./uploads/item_pics/$item->pic_filename");
|
||||||
|
|
||||||
if (sizeof($images) > 0) {
|
if (sizeof($images) > 0) {
|
||||||
$image .= '<a class="rollover" href="' . base_url($images[0]) . '"><img alt="Image thumbnail" src="' . site_url('items/PicThumb/' . pathinfo($images[0], PATHINFO_BASENAME)) . '"></a>';
|
$image_path = ltrim($images[0], './');
|
||||||
|
$image .= '<a class="rollover" href="' . base_url(implode('/', array_map('rawurlencode', explode('/', $image_path)))) . '"><img alt="Image thumbnail" src="' . site_url('items/PicThumb/' . rawurlencode(pathinfo($images[0], PATHINFO_BASENAME))) . '"></a>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,7 +479,7 @@ function get_item_data_row(object $item): array
|
|||||||
$item->name .= NAME_SEPARATOR . $item->pack_name;
|
$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 = [
|
$columns = [
|
||||||
'items.item_id' => $item->item_id,
|
'items.item_id' => $item->item_id,
|
||||||
@@ -633,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
|
* @param array $row
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
@@ -650,10 +651,16 @@ function expand_attribute_values(array $definition_names, array $row): array
|
|||||||
}
|
}
|
||||||
|
|
||||||
$attribute_values = [];
|
$attribute_values = [];
|
||||||
foreach ($definition_names as $definition_id => $definition_name) {
|
foreach ($definition_names as $definition_id => $definitionInfo) {
|
||||||
if (isset($indexed_values[$definition_id])) {
|
if (isset($indexed_values[$definition_id])) {
|
||||||
$attribute_value = $indexed_values[$definition_id];
|
$raw_value = $indexed_values[$definition_id];
|
||||||
$attribute_values["$definition_id"] = $attribute_value;
|
|
||||||
|
// 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 {
|
} else {
|
||||||
$attribute_values["$definition_id"] = "";
|
$attribute_values["$definition_id"] = "";
|
||||||
}
|
}
|
||||||
@@ -924,3 +931,24 @@ function get_controller(): string
|
|||||||
$controller_name_parts = explode('\\', $controller_name);
|
$controller_name_parts = explode('\\', $controller_name);
|
||||||
return end($controller_name_parts);
|
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_delete" => "هل أنت متأكد من أنك تريد حذف الميزات المحددة ؟",
|
||||||
"confirm_restore" => "هل أنت متأكد من أنك تريد استعادة السمة (السمات) المحددة؟",
|
"confirm_restore" => "هل أنت متأكد من أنك تريد استعادة السمة (السمات) المحددة؟",
|
||||||
"definition_cannot_be_deleted" => "لا يمكن حذف السمات المحددة",
|
"definition_cannot_be_deleted" => "لا يمكن حذف السمات المحددة",
|
||||||
|
"definition_invalid_group" => "المجموعة المحددة غير موجودة أو غير صالحة.",
|
||||||
"definition_error_adding_updating" => "لا يمكن إضافة السمة {0} أو تحديثها. يرجى التحقق من سجل الخطأ.",
|
"definition_error_adding_updating" => "لا يمكن إضافة السمة {0} أو تحديثها. يرجى التحقق من سجل الخطأ.",
|
||||||
"definition_flags" => "رؤية الميزات",
|
"definition_flags" => "رؤية الميزات",
|
||||||
"definition_group" => "المجموعة",
|
"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" => "ديسمبر",
|
||||||
|
];
|
||||||
@@ -14,6 +14,8 @@ return [
|
|||||||
"current_password_invalid" => "كلمة المرور الحالية غير صحيحة.",
|
"current_password_invalid" => "كلمة المرور الحالية غير صحيحة.",
|
||||||
"employee" => "موظف",
|
"employee" => "موظف",
|
||||||
"error_adding_updating" => "خطاء فى إضافة/تعديل موظف.",
|
"error_adding_updating" => "خطاء فى إضافة/تعديل موظف.",
|
||||||
|
"error_deleting_admin" => "",
|
||||||
|
"error_updating_admin" => "",
|
||||||
"error_deleting_demo_admin" => "لايمكن حذف المستخدم admin الخاص بنسخة العرض.",
|
"error_deleting_demo_admin" => "لايمكن حذف المستخدم admin الخاص بنسخة العرض.",
|
||||||
"error_updating_demo_admin" => "لايمكن تغيير بيانات المستخدم admin الخاص بنسخة العرض.",
|
"error_updating_demo_admin" => "لايمكن تغيير بيانات المستخدم admin الخاص بنسخة العرض.",
|
||||||
"language" => "اللغة",
|
"language" => "اللغة",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "سعر التكلفة مطلوب.",
|
"cost_price_required" => "سعر التكلفة مطلوب.",
|
||||||
"count" => "تحديث المخزون",
|
"count" => "تحديث المخزون",
|
||||||
"csv_import_failed" => "فشل الإستيراد من اكسل",
|
"csv_import_failed" => "فشل الإستيراد من اكسل",
|
||||||
|
"csv_import_invalid_location" => "",
|
||||||
"csv_import_nodata_wrongformat" => "الملف الذى رفعته إما فارغ أو أنه مختلف البنية.",
|
"csv_import_nodata_wrongformat" => "الملف الذى رفعته إما فارغ أو أنه مختلف البنية.",
|
||||||
"csv_import_partially_failed" => "يوجد خطأ بنسبة {0} في استيراد الاصناف في السطر: {1}. لم يتم استيرادهم.",
|
"csv_import_partially_failed" => "يوجد خطأ بنسبة {0} في استيراد الاصناف في السطر: {1}. لم يتم استيرادهم.",
|
||||||
"csv_import_success" => "تم استيراد الأصناف بنجاح.",
|
"csv_import_success" => "تم استيراد الأصناف بنجاح.",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ return [
|
|||||||
"confirm_delete" => "هل أنت متأكد من أنك تريد حذف الميزات المحددة ؟",
|
"confirm_delete" => "هل أنت متأكد من أنك تريد حذف الميزات المحددة ؟",
|
||||||
"confirm_restore" => "هل أنت متأكد من أنك تريد استعادة السمة (السمات) المحددة؟",
|
"confirm_restore" => "هل أنت متأكد من أنك تريد استعادة السمة (السمات) المحددة؟",
|
||||||
"definition_cannot_be_deleted" => "لا يمكن حذف السمات المحددة",
|
"definition_cannot_be_deleted" => "لا يمكن حذف السمات المحددة",
|
||||||
|
"definition_invalid_group" => "المجموعة المحددة غير موجودة أو غير صالحة.",
|
||||||
"definition_error_adding_updating" => "لا يمكن إضافة السمة {0} أو تحديثها. يرجى التحقق من سجل الخطأ.",
|
"definition_error_adding_updating" => "لا يمكن إضافة السمة {0} أو تحديثها. يرجى التحقق من سجل الخطأ.",
|
||||||
"definition_flags" => "رؤية الميزات",
|
"definition_flags" => "رؤية الميزات",
|
||||||
"definition_group" => "المجموعة",
|
"definition_group" => "المجموعة",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ return [
|
|||||||
"current_password_invalid" => "كلمة المرور الحالية غير صحيحة.",
|
"current_password_invalid" => "كلمة المرور الحالية غير صحيحة.",
|
||||||
"employee" => "موظف",
|
"employee" => "موظف",
|
||||||
"error_adding_updating" => "خطاء فى إضافة/تعديل موظف.",
|
"error_adding_updating" => "خطاء فى إضافة/تعديل موظف.",
|
||||||
|
"error_deleting_admin" => "",
|
||||||
|
"error_updating_admin" => "",
|
||||||
"error_deleting_demo_admin" => "لايمكن حذف المستخدم admin الخاص بنسخة العرض.",
|
"error_deleting_demo_admin" => "لايمكن حذف المستخدم admin الخاص بنسخة العرض.",
|
||||||
"error_updating_demo_admin" => "لايمكن تغيير بيانات المستخدم admin الخاص بنسخة العرض.",
|
"error_updating_demo_admin" => "لايمكن تغيير بيانات المستخدم admin الخاص بنسخة العرض.",
|
||||||
"language" => "اللغة",
|
"language" => "اللغة",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "سعر التكلفة مطلوب.",
|
"cost_price_required" => "سعر التكلفة مطلوب.",
|
||||||
"count" => "تحديث المخزون",
|
"count" => "تحديث المخزون",
|
||||||
"csv_import_failed" => "فشل الإستيراد من اكسل",
|
"csv_import_failed" => "فشل الإستيراد من اكسل",
|
||||||
|
"csv_import_invalid_location" => "",
|
||||||
"csv_import_nodata_wrongformat" => "الملف الذى رفعته إما فارغ أو أنه مختلف البنية.",
|
"csv_import_nodata_wrongformat" => "الملف الذى رفعته إما فارغ أو أنه مختلف البنية.",
|
||||||
"csv_import_partially_failed" => "يوجد خطأ بنسبة {0} في استيراد الاصناف في السطر: {1}. لم يتم استيرادهم.",
|
"csv_import_partially_failed" => "يوجد خطأ بنسبة {0} في استيراد الاصناف في السطر: {1}. لم يتم استيرادهم.",
|
||||||
"csv_import_success" => "تم استيراد الأصناف بنجاح.",
|
"csv_import_success" => "تم استيراد الأصناف بنجاح.",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ return [
|
|||||||
"confirm_delete" => "Seçilmiş Atributları silmək istədiyinizdən əminsinizmi?",
|
"confirm_delete" => "Seçilmiş Atributları silmək istədiyinizdən əminsinizmi?",
|
||||||
"confirm_restore" => "Seçilmiş atributları bərpa etmək istədiyinizə ə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_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_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_flags" => "Atribut görünüşü",
|
||||||
"definition_group" => "Qrup",
|
"definition_group" => "Qrup",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ return [
|
|||||||
"current_password_invalid" => "Hazirki Şifrə düzgün deyil.",
|
"current_password_invalid" => "Hazirki Şifrə düzgün deyil.",
|
||||||
"employee" => "Əməkdaş",
|
"employee" => "Əməkdaş",
|
||||||
"error_adding_updating" => "Əməkdaş əlavə etməsk və ya yeniləməsi baş vermədi.",
|
"error_adding_updating" => "Əməkdaş əlavə etməsk və ya yeniləməsi baş vermədi.",
|
||||||
|
"error_deleting_admin" => "",
|
||||||
|
"error_updating_admin" => "",
|
||||||
"error_deleting_demo_admin" => "Demo administrator istifadəçisini silə bilməzsiniz.",
|
"error_deleting_demo_admin" => "Demo administrator istifadəçisini silə bilməzsiniz.",
|
||||||
"error_updating_demo_admin" => "Demo administrator istifadəçisini dəyişə bilməzsiniz.",
|
"error_updating_demo_admin" => "Demo administrator istifadəçisini dəyişə bilməzsiniz.",
|
||||||
"language" => "Dil",
|
"language" => "Dil",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "Topdan satiış - doldurulması vacib sahə.",
|
"cost_price_required" => "Topdan satiış - doldurulması vacib sahə.",
|
||||||
"count" => "inventorun yenilənməsi",
|
"count" => "inventorun yenilənməsi",
|
||||||
"csv_import_failed" => "səhv csv import",
|
"csv_import_failed" => "səhv csv import",
|
||||||
|
"csv_import_invalid_location" => "",
|
||||||
"csv_import_nodata_wrongformat" => "Yüklənmiş faylda məlumat yoxdur və ya düzgün formatlanmır.",
|
"csv_import_nodata_wrongformat" => "Yüklənmiş faylda məlumat yoxdur və ya düzgün formatlanmır.",
|
||||||
"csv_import_partially_failed" => "Xətlərdə {0} element idxalı uğursuzluq (lar) var: {1}. Heç bir sıra idxal edilmədi.",
|
"csv_import_partially_failed" => "Xətlərdə {0} element idxalı uğursuzluq (lar) var: {1}. Heç bir sıra idxal edilmədi.",
|
||||||
"csv_import_success" => "Malların İdxalı Uğurla Həyata Keçdi.",
|
"csv_import_success" => "Malların İdxalı Uğurla Həyata Keçdi.",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ return [
|
|||||||
"confirm_delete" => "",
|
"confirm_delete" => "",
|
||||||
"confirm_restore" => "",
|
"confirm_restore" => "",
|
||||||
"definition_cannot_be_deleted" => "",
|
"definition_cannot_be_deleted" => "",
|
||||||
|
"definition_invalid_group" => "",
|
||||||
"definition_error_adding_updating" => "",
|
"definition_error_adding_updating" => "",
|
||||||
"definition_flags" => "",
|
"definition_flags" => "",
|
||||||
"definition_group" => "",
|
"definition_group" => "",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ return [
|
|||||||
"current_password_invalid" => "Текущата парола е невалидна.",
|
"current_password_invalid" => "Текущата парола е невалидна.",
|
||||||
"employee" => "Служител",
|
"employee" => "Служител",
|
||||||
"error_adding_updating" => "Добавянето или актуализирането на служителите е неуспешно.",
|
"error_adding_updating" => "Добавянето или актуализирането на служителите е неуспешно.",
|
||||||
|
"error_deleting_admin" => "",
|
||||||
|
"error_updating_admin" => "",
|
||||||
"error_deleting_demo_admin" => "Не може да изтриете Пробният Администратор.",
|
"error_deleting_demo_admin" => "Не може да изтриете Пробният Администратор.",
|
||||||
"error_updating_demo_admin" => "Не може да промените Пробният Администратор.",
|
"error_updating_demo_admin" => "Не може да промените Пробният Администратор.",
|
||||||
"language" => "Език",
|
"language" => "Език",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "Wholesale Price is a required field.",
|
"cost_price_required" => "Wholesale Price is a required field.",
|
||||||
"count" => "Update Inventory",
|
"count" => "Update Inventory",
|
||||||
"csv_import_failed" => "CSV import failed",
|
"csv_import_failed" => "CSV import failed",
|
||||||
|
"csv_import_invalid_location" => "",
|
||||||
"csv_import_nodata_wrongformat" => "The uploaded file has no data or is formatted incorrectly.",
|
"csv_import_nodata_wrongformat" => "The uploaded file has no data or is formatted incorrectly.",
|
||||||
"csv_import_partially_failed" => "Item import successful with some failures:",
|
"csv_import_partially_failed" => "Item import successful with some failures:",
|
||||||
"csv_import_success" => "Item import successful.",
|
"csv_import_success" => "Item import successful.",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ return [
|
|||||||
"confirm_delete" => "Da li ste sigurni da želite da izbrišete izabrani atribut?",
|
"confirm_delete" => "Da li ste sigurni da želite da izbrišete izabrani atribut?",
|
||||||
"confirm_restore" => "Da li ste sigurni da želite vratiti izabrane atribute?",
|
"confirm_restore" => "Da li ste sigurni da želite vratiti izabrane atribute?",
|
||||||
"definition_cannot_be_deleted" => "Nije moguće izbrisati izabrane atribut",
|
"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_error_adding_updating" => "Atribut {0} nije moguće dodati ili ažurirati. Molimo provjerite dnevnik grešaka.",
|
||||||
"definition_flags" => "Vidljivost atributa",
|
"definition_flags" => "Vidljivost atributa",
|
||||||
"definition_group" => "Grupa",
|
"definition_group" => "Grupa",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ return [
|
|||||||
"current_password_invalid" => "Trenutna lozinka je nevažeća.",
|
"current_password_invalid" => "Trenutna lozinka je nevažeća.",
|
||||||
"employee" => "Zaposlenik",
|
"employee" => "Zaposlenik",
|
||||||
"error_adding_updating" => "Dodavanje ili ažuriranje zaposlenika nije uspjelo.",
|
"error_adding_updating" => "Dodavanje ili ažuriranje zaposlenika nije uspjelo.",
|
||||||
|
"error_deleting_admin" => "",
|
||||||
|
"error_updating_admin" => "",
|
||||||
"error_deleting_demo_admin" => "Ne možete izbrisati demo korisnika administratora.",
|
"error_deleting_demo_admin" => "Ne možete izbrisati demo korisnika administratora.",
|
||||||
"error_updating_demo_admin" => "Ne možete promijeniti korisnika demo administratora.",
|
"error_updating_demo_admin" => "Ne možete promijeniti korisnika demo administratora.",
|
||||||
"language" => "Jezik",
|
"language" => "Jezik",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "Fakturna cijena je obavezno polje.",
|
"cost_price_required" => "Fakturna cijena je obavezno polje.",
|
||||||
"count" => "Ažuriraj zalihu",
|
"count" => "Ažuriraj zalihu",
|
||||||
"csv_import_failed" => "Uvoz CSV-a nije uspio",
|
"csv_import_failed" => "Uvoz CSV-a nije uspio",
|
||||||
|
"csv_import_invalid_location" => "",
|
||||||
"csv_import_nodata_wrongformat" => "Učitana CSV datoteka nema podatke ili je pogrešno formatirana.",
|
"csv_import_nodata_wrongformat" => "Učitana CSV datoteka nema podatke ili je pogrešno formatirana.",
|
||||||
"csv_import_partially_failed" => "Bilo je {0} grešaka pri uvozu stavke na liniji: {1}. Nijedan red nije uvezen.",
|
"csv_import_partially_failed" => "Bilo je {0} grešaka pri uvozu stavke na liniji: {1}. Nijedan red nije uvezen.",
|
||||||
"csv_import_success" => "Uvoz CSV stavke je uspješan.",
|
"csv_import_success" => "Uvoz CSV stavke je uspješan.",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ return [
|
|||||||
"confirm_delete" => "ئایا دڵنیای کە دەتەوێت تایبەتمەندییە هەڵبژێردراوەکە(کان) بسڕیتەوە؟",
|
"confirm_delete" => "ئایا دڵنیای کە دەتەوێت تایبەتمەندییە هەڵبژێردراوەکە(کان) بسڕیتەوە؟",
|
||||||
"confirm_restore" => "ئایا دڵنیای کە دەتەوێت تایبەتمەندییە هەڵبژێردراوەکە(کان) بگەڕێنیتەوە؟",
|
"confirm_restore" => "ئایا دڵنیای کە دەتەوێت تایبەتمەندییە هەڵبژێردراوەکە(کان) بگەڕێنیتەوە؟",
|
||||||
"definition_cannot_be_deleted" => "نەتوانرا تایبەتمەندی هەڵبژێردراو بسڕدرێتەوە",
|
"definition_cannot_be_deleted" => "نەتوانرا تایبەتمەندی هەڵبژێردراو بسڕدرێتەوە",
|
||||||
|
"definition_invalid_group" => "",
|
||||||
"definition_error_adding_updating" => "تایبەتمەندی {0} نەتوانرا زیاد بکرێت یان نوێ بکرێتەوە. تکایە لیستی هەڵەکان بپشکنە.",
|
"definition_error_adding_updating" => "تایبەتمەندی {0} نەتوانرا زیاد بکرێت یان نوێ بکرێتەوە. تکایە لیستی هەڵەکان بپشکنە.",
|
||||||
"definition_flags" => "توانای بینراویی تایبەتمەندی",
|
"definition_flags" => "توانای بینراویی تایبەتمەندی",
|
||||||
"definition_group" => "گروپ",
|
"definition_group" => "گروپ",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ return [
|
|||||||
'current_password_invalid' => "وشەی نهێنی ئێستا نادروستە.",
|
'current_password_invalid' => "وشەی نهێنی ئێستا نادروستە.",
|
||||||
'employee' => "فەرمانبەر",
|
'employee' => "فەرمانبەر",
|
||||||
'error_adding_updating' => "زیادکردن یان نوێکردنەوەی کارمەند سەرکەوتوو نەبوو.",
|
'error_adding_updating' => "زیادکردن یان نوێکردنەوەی کارمەند سەرکەوتوو نەبوو.",
|
||||||
|
'error_deleting_admin' => "",
|
||||||
|
'error_updating_admin' => "",
|
||||||
'error_deleting_demo_admin' => "ناتوانیت بەکارهێنەری ئەدمینی تاقیکردنەوەیی بسڕیتەوە.",
|
'error_deleting_demo_admin' => "ناتوانیت بەکارهێنەری ئەدمینی تاقیکردنەوەیی بسڕیتەوە.",
|
||||||
'error_updating_demo_admin' => "ناتوانیت بەکارهێنەری ئەدمین تاقیکردنەوەیی بگۆڕیت.",
|
'error_updating_demo_admin' => "ناتوانیت بەکارهێنەری ئەدمین تاقیکردنەوەیی بگۆڕیت.",
|
||||||
'language' => "زمان",
|
'language' => "زمان",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
'cost_price_required' => "نرخی جوملە خانەیەکی پێویستە.",
|
'cost_price_required' => "نرخی جوملە خانەیەکی پێویستە.",
|
||||||
'count' => "جەرد نوێ بکەوە",
|
'count' => "جەرد نوێ بکەوە",
|
||||||
'csv_import_failed' => "هاوردەکردنی CSV سەرکەوتوو نەبوو",
|
'csv_import_failed' => "هاوردەکردنی CSV سەرکەوتوو نەبوو",
|
||||||
|
'csv_import_invalid_location' => "",
|
||||||
'csv_import_nodata_wrongformat' => "پەڕگەی CSV بارکراو هیچ داتایەکی نییە یان بە هەڵە فۆرمات کراوە.",
|
'csv_import_nodata_wrongformat' => "پەڕگەی CSV بارکراو هیچ داتایەکی نییە یان بە هەڵە فۆرمات کراوە.",
|
||||||
'csv_import_partially_failed' => "{0} شکستی هاوردەکردنی بابەتی لەسەر هێڵەکان هەبوو: {1}. هیچ ڕیزێک هاوردە نەکرا.",
|
'csv_import_partially_failed' => "{0} شکستی هاوردەکردنی بابەتی لەسەر هێڵەکان هەبوو: {1}. هیچ ڕیزێک هاوردە نەکرا.",
|
||||||
'csv_import_success' => "بابەتی هاوردەکردنی CSV سەرکەوتوو بوو.",
|
'csv_import_success' => "بابەتی هاوردەکردنی CSV سەرکەوتوو بوو.",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ return [
|
|||||||
"confirm_delete" => "",
|
"confirm_delete" => "",
|
||||||
"confirm_restore" => "",
|
"confirm_restore" => "",
|
||||||
"definition_cannot_be_deleted" => "",
|
"definition_cannot_be_deleted" => "",
|
||||||
|
"definition_invalid_group" => "",
|
||||||
"definition_error_adding_updating" => "",
|
"definition_error_adding_updating" => "",
|
||||||
"definition_flags" => "",
|
"definition_flags" => "",
|
||||||
"definition_group" => "",
|
"definition_group" => "",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ return [
|
|||||||
"current_password_invalid" => "",
|
"current_password_invalid" => "",
|
||||||
"employee" => "",
|
"employee" => "",
|
||||||
"error_adding_updating" => "",
|
"error_adding_updating" => "",
|
||||||
|
"error_deleting_admin" => "",
|
||||||
|
"error_updating_admin" => "",
|
||||||
"error_deleting_demo_admin" => "",
|
"error_deleting_demo_admin" => "",
|
||||||
"error_updating_demo_admin" => "",
|
"error_updating_demo_admin" => "",
|
||||||
"language" => "",
|
"language" => "",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "Musíte zadat nákupní cenu.",
|
"cost_price_required" => "Musíte zadat nákupní cenu.",
|
||||||
"count" => "Upravit množství",
|
"count" => "Upravit množství",
|
||||||
"csv_import_failed" => "Import z CSVu se nepovedl",
|
"csv_import_failed" => "Import z CSVu se nepovedl",
|
||||||
|
"csv_import_invalid_location" => "",
|
||||||
"csv_import_nodata_wrongformat" => "Nahraný soubor neobsahuje žádná data nebo má špatný formát.",
|
"csv_import_nodata_wrongformat" => "Nahraný soubor neobsahuje žádná data nebo má špatný formát.",
|
||||||
"csv_import_partially_failed" => "Při importu položek došlo k několika chybám:",
|
"csv_import_partially_failed" => "Při importu položek došlo k několika chybám:",
|
||||||
"csv_import_success" => "Import položek proběhl bez chyby.",
|
"csv_import_success" => "Import položek proběhl bez chyby.",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ return [
|
|||||||
"confirm_delete" => "Er du sikker på, at du vil slette de valgte egenskaber?",
|
"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?",
|
"confirm_restore" => "Er du sikker på, at du vil gendanne de valgte egenskaber?",
|
||||||
"definition_cannot_be_deleted" => "De valgte egenskaber kunne ikke slettes",
|
"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_error_adding_updating" => "Egenskab {0} Kunne ikke tilføjes eller opdateres. Tjek venligst fejlprotokollen.",
|
||||||
"definition_flags" => "Egenskabens Synlighed",
|
"definition_flags" => "Egenskabens Synlighed",
|
||||||
"definition_group" => "Gruppe",
|
"definition_group" => "Gruppe",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ return [
|
|||||||
"current_password_invalid" => "Current Password is invalid.",
|
"current_password_invalid" => "Current Password is invalid.",
|
||||||
"employee" => "Employee",
|
"employee" => "Employee",
|
||||||
"error_adding_updating" => "Employee add or update failed.",
|
"error_adding_updating" => "Employee add or update failed.",
|
||||||
|
"error_deleting_admin" => "",
|
||||||
|
"error_updating_admin" => "",
|
||||||
"error_deleting_demo_admin" => "You can not delete the demo admin user.",
|
"error_deleting_demo_admin" => "You can not delete the demo admin user.",
|
||||||
"error_updating_demo_admin" => "You can not change the demo admin user.",
|
"error_updating_demo_admin" => "You can not change the demo admin user.",
|
||||||
"language" => "Language",
|
"language" => "Language",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "",
|
"cost_price_required" => "",
|
||||||
"count" => "",
|
"count" => "",
|
||||||
"csv_import_failed" => "",
|
"csv_import_failed" => "",
|
||||||
|
"csv_import_invalid_location" => "",
|
||||||
"csv_import_nodata_wrongformat" => "",
|
"csv_import_nodata_wrongformat" => "",
|
||||||
"csv_import_partially_failed" => "",
|
"csv_import_partially_failed" => "",
|
||||||
"csv_import_success" => "",
|
"csv_import_success" => "",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ return [
|
|||||||
"confirm_delete" => "",
|
"confirm_delete" => "",
|
||||||
"confirm_restore" => "",
|
"confirm_restore" => "",
|
||||||
"definition_cannot_be_deleted" => "",
|
"definition_cannot_be_deleted" => "",
|
||||||
|
"definition_invalid_group" => "Die ausgewählte Gruppe existiert nicht oder ist ungültig.",
|
||||||
"definition_error_adding_updating" => "",
|
"definition_error_adding_updating" => "",
|
||||||
"definition_flags" => "",
|
"definition_flags" => "",
|
||||||
"definition_group" => "",
|
"definition_group" => "",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ return [
|
|||||||
"current_password_invalid" => "",
|
"current_password_invalid" => "",
|
||||||
"employee" => "Mitarbeiter",
|
"employee" => "Mitarbeiter",
|
||||||
"error_adding_updating" => "Fehler beim Hinzufügen/Ändern",
|
"error_adding_updating" => "Fehler beim Hinzufügen/Ändern",
|
||||||
|
"error_deleting_admin" => "",
|
||||||
|
"error_updating_admin" => "",
|
||||||
"error_deleting_demo_admin" => "Sie können den Admin nicht löschen",
|
"error_deleting_demo_admin" => "Sie können den Admin nicht löschen",
|
||||||
"error_updating_demo_admin" => "Sie können den Admin nicht ändern",
|
"error_updating_demo_admin" => "Sie können den Admin nicht ändern",
|
||||||
"language" => "",
|
"language" => "",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "Einstandspreis ist erforderlich",
|
"cost_price_required" => "Einstandspreis ist erforderlich",
|
||||||
"count" => "Ändere Bestand",
|
"count" => "Ändere Bestand",
|
||||||
"csv_import_failed" => "CSV Import fehlerhaft",
|
"csv_import_failed" => "CSV Import fehlerhaft",
|
||||||
|
"csv_import_invalid_location" => "",
|
||||||
"csv_import_nodata_wrongformat" => "Your uploaded file has no data or wrong format",
|
"csv_import_nodata_wrongformat" => "Your uploaded file has no data or wrong format",
|
||||||
"csv_import_partially_failed" => "Most Items imported. But some were not, here is the list",
|
"csv_import_partially_failed" => "Most Items imported. But some were not, here is the list",
|
||||||
"csv_import_success" => "Import of Items successful",
|
"csv_import_success" => "Import of Items successful",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ return [
|
|||||||
"confirm_delete" => "Sind Sie sicher, dass Sie die ausgewählten Attribute löschen möchten?",
|
"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?",
|
"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_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_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_flags" => "Attribut Sichtbarkeit",
|
||||||
"definition_group" => "Gruppe",
|
"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 [
|
return [
|
||||||
"address_1" => "Adresse 1",
|
"address_1" => "Adresse 1",
|
||||||
"address_2" => "Adresse 2",
|
"address_2" => "Adresse 2",
|
||||||
"admin" => "",
|
"admin" => "Administrator",
|
||||||
"city" => "Stadt",
|
"city" => "Stadt",
|
||||||
"clerk" => "",
|
"clerk" => "Angestellter",
|
||||||
"close" => "Schließen",
|
"close" => "Schließen",
|
||||||
"color" => "",
|
"color" => "Theme-Farben",
|
||||||
"comments" => "Kommentare",
|
"comments" => "Kommentare",
|
||||||
"common" => "Allgemein",
|
"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?",
|
"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}",
|
"copyrights" => "© 2010 - {0}",
|
||||||
"correct_errors" => "Bitte korrigieren Sie vor dem Speichern die angezeigten Fehler",
|
"correct_errors" => "Bitte korrigieren Sie vor dem Speichern die angezeigten Fehler",
|
||||||
"country" => "Land",
|
"country" => "Land",
|
||||||
"dashboard" => "",
|
"dashboard" => "Dashboard",
|
||||||
"date" => "Datum",
|
"date" => "Datum",
|
||||||
"delete" => "Löschen",
|
"delete" => "Löschen",
|
||||||
"det" => "Details",
|
"det" => "Details",
|
||||||
@@ -26,15 +26,15 @@ return [
|
|||||||
"export_csv_no" => "Nein",
|
"export_csv_no" => "Nein",
|
||||||
"export_csv_yes" => "Ja",
|
"export_csv_yes" => "Ja",
|
||||||
"fields_required_message" => "Die Felder in rot sind erforderlich",
|
"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" => "Vorname",
|
||||||
"first_name_required" => "Vorname ist erforderlich.",
|
"first_name_required" => "Vorname ist erforderlich.",
|
||||||
"first_page" => "Erste",
|
"first_page" => "Erste",
|
||||||
"gender" => "Geschlecht",
|
"gender" => "Geschlecht",
|
||||||
"gender_female" => "W",
|
"gender_female" => "W",
|
||||||
"gender_male" => "M",
|
"gender_male" => "M",
|
||||||
"gender_undefined" => "",
|
"gender_undefined" => "Undefiniert",
|
||||||
"icon" => "",
|
"icon" => "Symbol",
|
||||||
"id" => "ID",
|
"id" => "ID",
|
||||||
"import" => "Import",
|
"import" => "Import",
|
||||||
"import_change_file" => "Ändern",
|
"import_change_file" => "Ändern",
|
||||||
@@ -48,21 +48,21 @@ return [
|
|||||||
"last_page" => "Letzte",
|
"last_page" => "Letzte",
|
||||||
"learn_about_project" => "für neueste Nachrichten zum Projekt.",
|
"learn_about_project" => "für neueste Nachrichten zum Projekt.",
|
||||||
"list_of" => "Liste von",
|
"list_of" => "Liste von",
|
||||||
"logo" => "",
|
"logo" => "Logo",
|
||||||
"logo_mark" => "",
|
"logo_mark" => "Marke",
|
||||||
"logout" => "Ausloggen",
|
"logout" => "Ausloggen",
|
||||||
"manager" => "",
|
"manager" => "Manager",
|
||||||
"migration_needed" => "Eine Datenbankmigration auf {0} wird nach der Anmeldung gestartet.",
|
"migration_needed" => "Eine Datenbankmigration auf {0} wird nach der Anmeldung gestartet.",
|
||||||
"new" => "Neu",
|
"new" => "Neu",
|
||||||
"no" => "",
|
"no" => "Nein",
|
||||||
"no_persons_to_display" => "Keine Personen zum Anzeigen.",
|
"no_persons_to_display" => "Keine Personen zum Anzeigen.",
|
||||||
"none_selected_text" => "[auswählen]",
|
"none_selected_text" => "[auswählen]",
|
||||||
"or" => "Oder",
|
"or" => "Oder",
|
||||||
"people" => "",
|
"people" => "Personen",
|
||||||
"phone_number" => "Telefon",
|
"phone_number" => "Telefon",
|
||||||
"phone_number_required" => "Telefon ist erforderlich",
|
"phone_number_required" => "Telefon ist erforderlich",
|
||||||
"please_visit_my" => "Bitte beuschen Sie",
|
"please_visit_my" => "Bitte beuschen Sie",
|
||||||
"position" => "",
|
"position" => "Position",
|
||||||
"powered_by" => "Unterstützt von",
|
"powered_by" => "Unterstützt von",
|
||||||
"price" => "Preis",
|
"price" => "Preis",
|
||||||
"print" => "Drucken",
|
"print" => "Drucken",
|
||||||
@@ -73,8 +73,8 @@ return [
|
|||||||
"search" => "Suche",
|
"search" => "Suche",
|
||||||
"search_options" => "Suchkriterien",
|
"search_options" => "Suchkriterien",
|
||||||
"searched_for" => "Gescuht nach",
|
"searched_for" => "Gescuht nach",
|
||||||
"software_short" => "",
|
"software_short" => "OSPOS",
|
||||||
"software_title" => "",
|
"software_title" => "Open Source Point of Sale",
|
||||||
"state" => "BL/Kanton",
|
"state" => "BL/Kanton",
|
||||||
"submit" => "Senden",
|
"submit" => "Senden",
|
||||||
"total_spent" => "Gesamtausgaben",
|
"total_spent" => "Gesamtausgaben",
|
||||||
@@ -83,7 +83,7 @@ return [
|
|||||||
"website" => "Website",
|
"website" => "Website",
|
||||||
"welcome" => "Willkommen",
|
"welcome" => "Willkommen",
|
||||||
"welcome_message" => "Willkommen bei OSPOS, zum Beginnen auf ein Modul klicken.",
|
"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",
|
"you_are_using_ospos" => "Sie verwenden Open Source Point Of Sale Version",
|
||||||
"zip" => "PLZ",
|
"zip" => "PLZ",
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
"administrator" => "",
|
"administrator" => "Administrator",
|
||||||
"basic_information" => "Mitarbeiter-Information",
|
"basic_information" => "Mitarbeiter-Information",
|
||||||
"cannot_be_deleted" => "Konnte gewählten Mitarbeiter nicht löschen, einer oder mehrere weisen Verkäufe aus.",
|
"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",
|
"change_password" => "Passwort Ändern",
|
||||||
"clerk" => "",
|
"clerk" => "Angestellter",
|
||||||
"commission" => "",
|
"commission" => "Provision",
|
||||||
"confirm_delete" => "Wollen Sie diesen Mitarbeiter wirklich löschen?",
|
"confirm_delete" => "Wollen Sie diesen Mitarbeiter wirklich löschen?",
|
||||||
"confirm_restore" => "Möchten Sie die ausgewählten Mitarbeiter wiederherstellen?",
|
"confirm_restore" => "Möchten Sie die ausgewählten Mitarbeiter wiederherstellen?",
|
||||||
"current_password" => "Aktuelles Passwort",
|
"current_password" => "Aktuelles Passwort",
|
||||||
"current_password_invalid" => "Aktuelles Passwort ist ungültig.",
|
"current_password_invalid" => "Aktuelles Passwort ist ungültig.",
|
||||||
"employee" => "Mitarbeiter",
|
"employee" => "Mitarbeiter",
|
||||||
"error_adding_updating" => "Fehler beim Hinzufügen/Ändern.",
|
"error_adding_updating" => "Fehler beim Hinzufügen/Ändern.",
|
||||||
|
"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_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.",
|
"error_updating_demo_admin" => "Sie können den Demo-Administrator nicht verändern.",
|
||||||
"language" => "Sprache",
|
"language" => "Sprache",
|
||||||
"login_info" => "Mitarbeiter Login",
|
"login_info" => "Mitarbeiter Login",
|
||||||
"manager" => "",
|
"manager" => "Manager",
|
||||||
"new" => "Neuer Mitarbeiter",
|
"new" => "Neuer Mitarbeiter",
|
||||||
"none_selected" => "Sie haben keine Mitarbeiter zum Löschen gewählt.",
|
"none_selected" => "Sie haben keine Mitarbeiter zum Löschen gewählt.",
|
||||||
"one_or_multiple" => "Mitarbeiter",
|
"one_or_multiple" => "Mitarbeiter",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "Der Großhandelspreis ist ein Pflichtfeld.",
|
"cost_price_required" => "Der Großhandelspreis ist ein Pflichtfeld.",
|
||||||
"count" => "Ändere Bestand",
|
"count" => "Ändere Bestand",
|
||||||
"csv_import_failed" => "CSV Import fehlgeschlagen",
|
"csv_import_failed" => "CSV Import fehlgeschlagen",
|
||||||
|
"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_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_partially_failed" => "{0} Artikel-Import Fehler in Zeile: {1}. Keine Reihen wurden importiert.",
|
||||||
"csv_import_success" => "Artikelimport erfolgreich.",
|
"csv_import_success" => "Artikelimport erfolgreich.",
|
||||||
|
|||||||
@@ -146,4 +146,5 @@ return [
|
|||||||
"used" => "Punkte eingelöst",
|
"used" => "Punkte eingelöst",
|
||||||
"work_orders" => "Arbeitsaufträge",
|
"work_orders" => "Arbeitsaufträge",
|
||||||
"zero_and_less" => "Null und weniger",
|
"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_number_duplicate" => "Arbeitsauftragsnummer muss eindeutig sein.",
|
||||||
"work_order_sent" => "Arbeitsauftrag gesendet an",
|
"work_order_sent" => "Arbeitsauftrag gesendet an",
|
||||||
"work_order_unsent" => "Der Arbeitsauftrag konnte nicht gesendet werden 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_delete" => "Είστε βέβαιοι ότι θέλετε να διαγράψετε τα επιλεγμένα χαρακτηριστικά;",
|
||||||
"confirm_restore" => "Είστε βέβαιοι ότι θέλετε να επαναφέρετε τα επιλεγμένα χαρακτηριστικά;",
|
"confirm_restore" => "Είστε βέβαιοι ότι θέλετε να επαναφέρετε τα επιλεγμένα χαρακτηριστικά;",
|
||||||
"definition_cannot_be_deleted" => "Δεν ήταν δυνατή η διαγραφή των επιλεγμένων χαρακτηριστικών",
|
"definition_cannot_be_deleted" => "Δεν ήταν δυνατή η διαγραφή των επιλεγμένων χαρακτηριστικών",
|
||||||
|
"definition_invalid_group" => "Η επιλεγμένη ομάδα δεν υπάρχει ή δεν είναι έγκυρη.",
|
||||||
"definition_error_adding_updating" => "Το χαρακτηριστικό {0} δεν ήταν δυνατό να προστεθεί ή να ενημερωθεί. Ελέγξτε το αρχείο καταγραφής σφαλμάτων.",
|
"definition_error_adding_updating" => "Το χαρακτηριστικό {0} δεν ήταν δυνατό να προστεθεί ή να ενημερωθεί. Ελέγξτε το αρχείο καταγραφής σφαλμάτων.",
|
||||||
"definition_flags" => "Ορατότητα χαρακτηριστικών",
|
"definition_flags" => "Ορατότητα χαρακτηριστικών",
|
||||||
"definition_group" => "Ομάδα",
|
"definition_group" => "Ομάδα",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ return [
|
|||||||
"current_password_invalid" => "",
|
"current_password_invalid" => "",
|
||||||
"employee" => "",
|
"employee" => "",
|
||||||
"error_adding_updating" => "",
|
"error_adding_updating" => "",
|
||||||
|
"error_deleting_admin" => "",
|
||||||
|
"error_updating_admin" => "",
|
||||||
"error_deleting_demo_admin" => "",
|
"error_deleting_demo_admin" => "",
|
||||||
"error_updating_demo_admin" => "",
|
"error_updating_demo_admin" => "",
|
||||||
"language" => "",
|
"language" => "",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "",
|
"cost_price_required" => "",
|
||||||
"count" => "",
|
"count" => "",
|
||||||
"csv_import_failed" => "",
|
"csv_import_failed" => "",
|
||||||
|
"csv_import_invalid_location" => "",
|
||||||
"csv_import_nodata_wrongformat" => "",
|
"csv_import_nodata_wrongformat" => "",
|
||||||
"csv_import_partially_failed" => "",
|
"csv_import_partially_failed" => "",
|
||||||
"csv_import_success" => "",
|
"csv_import_success" => "",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ return [
|
|||||||
"confirm_restore" => "Are you sure you want to restore 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_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_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_flags" => "Attribute Visibility",
|
||||||
"definition_group" => "Group",
|
"definition_group" => "Group",
|
||||||
"definition_id" => "Id",
|
"definition_id" => "Id",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ return [
|
|||||||
"confirm_restore" => "Are you sure you want to restore 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_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_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_flags" => "Attribute Visibility",
|
||||||
"definition_group" => "Group",
|
"definition_group" => "Group",
|
||||||
"definition_id" => "Id",
|
"definition_id" => "Id",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ return [
|
|||||||
"confirm_delete" => "¿Está seguro de que desea borrar los atributos seleccionados?",
|
"confirm_delete" => "¿Está seguro de que desea borrar los atributos seleccionados?",
|
||||||
"confirm_restore" => "¿Está seguro de que desea restaurar 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_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_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_flags" => "Visibilidad del atributo",
|
||||||
"definition_group" => "Grupo",
|
"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,6 +14,8 @@ return [
|
|||||||
"current_password_invalid" => "Contraseña Actual Inválida.",
|
"current_password_invalid" => "Contraseña Actual Inválida.",
|
||||||
"employee" => "Empleado",
|
"employee" => "Empleado",
|
||||||
"error_adding_updating" => "Error al agregar/actualizar empleado.",
|
"error_adding_updating" => "Error al agregar/actualizar empleado.",
|
||||||
|
"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_deleting_demo_admin" => "No puedes borrar el usuario admin del demo.",
|
||||||
"error_updating_demo_admin" => "No puedes cambiar el usuario admin del demo.",
|
"error_updating_demo_admin" => "No puedes cambiar el usuario admin del demo.",
|
||||||
"language" => "Idioma",
|
"language" => "Idioma",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "Precio al Por Mayor es un campo requerido.",
|
"cost_price_required" => "Precio al Por Mayor es un campo requerido.",
|
||||||
"count" => "Actualizar Inventario",
|
"count" => "Actualizar Inventario",
|
||||||
"csv_import_failed" => "Falló la importación de Hoja de Cálculo",
|
"csv_import_failed" => "Falló la importación de Hoja de Cálculo",
|
||||||
|
"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_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_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.",
|
"csv_import_success" => "Se importaron los articulos exitosamente.",
|
||||||
|
|||||||
@@ -146,4 +146,5 @@ return [
|
|||||||
"used" => "Puntos usados",
|
"used" => "Puntos usados",
|
||||||
"work_orders" => "Ordenes",
|
"work_orders" => "Ordenes",
|
||||||
"zero_and_less" => "Cero y negativos",
|
"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_number_duplicate" => "El numero de orden de trabajo debe ser unico.",
|
||||||
"work_order_sent" => "Orden de trabajo enviada a",
|
"work_order_sent" => "Orden de trabajo enviada a",
|
||||||
"work_order_unsent" => "Orden de trabajo fallida al enviar 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",
|
"selected_customer" => "Cliente seleccionado",
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ return [
|
|||||||
"confirm_delete" => "¿Está seguro de eliminar el/los atributo(s) seleccionado(s)?",
|
"confirm_delete" => "¿Está seguro de eliminar el/los atributo(s) seleccionado(s)?",
|
||||||
"confirm_restore" => "¿Está seguro que quiere restaurar los atributos seleccionados?",
|
"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_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_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_flags" => "Visibilidad del atributo",
|
||||||
"definition_group" => "Grupo",
|
"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",
|
||||||
|
];
|
||||||
@@ -14,6 +14,8 @@ return [
|
|||||||
"current_password_invalid" => "La contraseña actual es inválida.",
|
"current_password_invalid" => "La contraseña actual es inválida.",
|
||||||
"employee" => "Empleado",
|
"employee" => "Empleado",
|
||||||
"error_adding_updating" => "Agregar ó Actualizar empleado ha fallado.",
|
"error_adding_updating" => "Agregar ó Actualizar empleado ha fallado.",
|
||||||
|
"error_deleting_admin" => "",
|
||||||
|
"error_updating_admin" => "",
|
||||||
"error_deleting_demo_admin" => "No puede borrar el usuario demo de administrador.",
|
"error_deleting_demo_admin" => "No puede borrar el usuario demo de administrador.",
|
||||||
"error_updating_demo_admin" => "No puede cambiar el usuario demo de administrador.",
|
"error_updating_demo_admin" => "No puede cambiar el usuario demo de administrador.",
|
||||||
"language" => "Idioma",
|
"language" => "Idioma",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "El precio de mayoreo es requerido.",
|
"cost_price_required" => "El precio de mayoreo es requerido.",
|
||||||
"count" => "Actualizar inventario",
|
"count" => "Actualizar inventario",
|
||||||
"csv_import_failed" => "",
|
"csv_import_failed" => "",
|
||||||
|
"csv_import_invalid_location" => "",
|
||||||
"csv_import_nodata_wrongformat" => "",
|
"csv_import_nodata_wrongformat" => "",
|
||||||
"csv_import_partially_failed" => "",
|
"csv_import_partially_failed" => "",
|
||||||
"csv_import_success" => "",
|
"csv_import_success" => "",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ return [
|
|||||||
"confirm_delete" => "آیا مطمئن هستید که می خواهید ویژگی (های) انتخاب شده را حذف کنید؟",
|
"confirm_delete" => "آیا مطمئن هستید که می خواهید ویژگی (های) انتخاب شده را حذف کنید؟",
|
||||||
"confirm_restore" => "آیا مطمئن هستید که می خواهید ویژگی (های) انتخاب شده را بازیابی کنید؟",
|
"confirm_restore" => "آیا مطمئن هستید که می خواهید ویژگی (های) انتخاب شده را بازیابی کنید؟",
|
||||||
"definition_cannot_be_deleted" => "نمی توان ویژگی (های) انتخابی را حذف کرد",
|
"definition_cannot_be_deleted" => "نمی توان ویژگی (های) انتخابی را حذف کرد",
|
||||||
|
"definition_invalid_group" => "گروه انتخاب شده وجود ندارد یا نامعتبر است.",
|
||||||
"definition_error_adding_updating" => "ویژگی{0} اضافه نشد یا به روز نمی شود. لطفا گزارش خطا را بررسی کنید.",
|
"definition_error_adding_updating" => "ویژگی{0} اضافه نشد یا به روز نمی شود. لطفا گزارش خطا را بررسی کنید.",
|
||||||
"definition_flags" => "قابلیت مشاهده ویژگی",
|
"definition_flags" => "قابلیت مشاهده ویژگی",
|
||||||
"definition_group" => "گروه",
|
"definition_group" => "گروه",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ return [
|
|||||||
"current_password_invalid" => "گذرواژه فعلی نامعتبر است.",
|
"current_password_invalid" => "گذرواژه فعلی نامعتبر است.",
|
||||||
"employee" => "کارمند",
|
"employee" => "کارمند",
|
||||||
"error_adding_updating" => "افزودن یا به روزرسانی کارکنان انجام نشد.",
|
"error_adding_updating" => "افزودن یا به روزرسانی کارکنان انجام نشد.",
|
||||||
|
"error_deleting_admin" => "",
|
||||||
|
"error_updating_admin" => "",
|
||||||
"error_deleting_demo_admin" => "شما نمی توانید کاربر مدیر نسخه ی نمایشی را حذف کنید.",
|
"error_deleting_demo_admin" => "شما نمی توانید کاربر مدیر نسخه ی نمایشی را حذف کنید.",
|
||||||
"error_updating_demo_admin" => "شما نمی توانید کاربر مدیر نسخه ی نمایشی را تغییر دهید.",
|
"error_updating_demo_admin" => "شما نمی توانید کاربر مدیر نسخه ی نمایشی را تغییر دهید.",
|
||||||
"language" => "زبان",
|
"language" => "زبان",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "قیمت عمده فروشی یک زمینه ضروری است.",
|
"cost_price_required" => "قیمت عمده فروشی یک زمینه ضروری است.",
|
||||||
"count" => "به روزرسانی موجودی",
|
"count" => "به روزرسانی موجودی",
|
||||||
"csv_import_failed" => "واردات سیاسوی انجام نشد",
|
"csv_import_failed" => "واردات سیاسوی انجام نشد",
|
||||||
|
"csv_import_invalid_location" => "",
|
||||||
"csv_import_nodata_wrongformat" => "پرونده سیاسوی آپلود شده داده ای ندارد یا به طور نادرست قالب بندی شده است.",
|
"csv_import_nodata_wrongformat" => "پرونده سیاسوی آپلود شده داده ای ندارد یا به طور نادرست قالب بندی شده است.",
|
||||||
"csv_import_partially_failed" => "در خط (ها){0} شکست واردات کالا وجود دارد:{1}. هیچ سطر وارد نشده است.",
|
"csv_import_partially_failed" => "در خط (ها){0} شکست واردات کالا وجود دارد:{1}. هیچ سطر وارد نشده است.",
|
||||||
"csv_import_success" => "وارد کردن سیاسوی مورد موفقیت آمیز است.",
|
"csv_import_success" => "وارد کردن سیاسوی مورد موفقیت آمیز است.",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ return [
|
|||||||
"confirm_delete" => "Êtes-vous certain de vouloir supprimer le(s) attribut(s) sélectionné(s) ?",
|
"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) ?",
|
"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_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_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_flags" => "Visibilité de l'attribut",
|
||||||
"definition_group" => "Groupe",
|
"definition_group" => "Groupe",
|
||||||
|
|||||||
@@ -3,18 +3,18 @@
|
|||||||
return [
|
return [
|
||||||
"address_1" => "Adresse 1",
|
"address_1" => "Adresse 1",
|
||||||
"address_2" => "Adresse 2",
|
"address_2" => "Adresse 2",
|
||||||
"admin" => "",
|
"admin" => "Administrateur",
|
||||||
"city" => "Ville",
|
"city" => "Ville",
|
||||||
"clerk" => "",
|
"clerk" => "Employé",
|
||||||
"close" => "Fermer",
|
"close" => "Fermer",
|
||||||
"color" => "",
|
"color" => "Couleurs du thème",
|
||||||
"comments" => "Commentaires",
|
"comments" => "Commentaires",
|
||||||
"common" => "commun",
|
"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 ?",
|
"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}",
|
"copyrights" => "© 2010 - {0}",
|
||||||
"correct_errors" => "Merci de corriger les erreurs identifiées avant d'enregistrer",
|
"correct_errors" => "Merci de corriger les erreurs identifiées avant d'enregistrer",
|
||||||
"country" => "Pays",
|
"country" => "Pays",
|
||||||
"dashboard" => "",
|
"dashboard" => "Tableau de bord",
|
||||||
"date" => "Date",
|
"date" => "Date",
|
||||||
"delete" => "Supprimer",
|
"delete" => "Supprimer",
|
||||||
"det" => "détails",
|
"det" => "détails",
|
||||||
@@ -26,14 +26,14 @@ return [
|
|||||||
"export_csv_no" => "Non",
|
"export_csv_no" => "Non",
|
||||||
"export_csv_yes" => "Oui",
|
"export_csv_yes" => "Oui",
|
||||||
"fields_required_message" => "Les champs en rouge sont requis",
|
"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" => "Prénom",
|
||||||
"first_name_required" => "Le prénom est requis.",
|
"first_name_required" => "Le prénom est requis.",
|
||||||
"first_page" => "Premier",
|
"first_page" => "Premier",
|
||||||
"gender" => "Genre",
|
"gender" => "Genre",
|
||||||
"gender_female" => "F",
|
"gender_female" => "F",
|
||||||
"gender_male" => "M",
|
"gender_male" => "M",
|
||||||
"gender_undefined" => "",
|
"gender_undefined" => "Non défini",
|
||||||
"icon" => "Icône",
|
"icon" => "Icône",
|
||||||
"id" => "Identifiant",
|
"id" => "Identifiant",
|
||||||
"import" => "Importation",
|
"import" => "Importation",
|
||||||
@@ -51,18 +51,18 @@ return [
|
|||||||
"logo" => "Logo",
|
"logo" => "Logo",
|
||||||
"logo_mark" => "Marque",
|
"logo_mark" => "Marque",
|
||||||
"logout" => "Déconnexion",
|
"logout" => "Déconnexion",
|
||||||
"manager" => "",
|
"manager" => "Gestionnaire",
|
||||||
"migration_needed" => "Une migration de la base de donnée vers {0} démarrera après le connexion.",
|
"migration_needed" => "Une migration de la base de donnée vers {0} démarrera après le connexion.",
|
||||||
"new" => "Nouveau",
|
"new" => "Nouveau",
|
||||||
"no" => "Oui",
|
"no" => "Non",
|
||||||
"no_persons_to_display" => "Il n'y a personne à afficher.",
|
"no_persons_to_display" => "Il n'y a personne à afficher.",
|
||||||
"none_selected_text" => "[Sélectionner]",
|
"none_selected_text" => "[Sélectionner]",
|
||||||
"or" => "OU",
|
"or" => "OU",
|
||||||
"people" => "",
|
"people" => "Personnes",
|
||||||
"phone_number" => "Téléphone",
|
"phone_number" => "Téléphone",
|
||||||
"phone_number_required" => "Le numéro de téléphone est requis.",
|
"phone_number_required" => "Le numéro de téléphone est requis.",
|
||||||
"please_visit_my" => "SVP visitez le",
|
"please_visit_my" => "SVP visitez le",
|
||||||
"position" => "",
|
"position" => "Position",
|
||||||
"powered_by" => "Propulsé par",
|
"powered_by" => "Propulsé par",
|
||||||
"price" => "Prix",
|
"price" => "Prix",
|
||||||
"print" => "Imprimer",
|
"print" => "Imprimer",
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
"administrator" => "",
|
"administrator" => "Administrateur",
|
||||||
"basic_information" => "Fiche",
|
"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.",
|
"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",
|
"change_password" => "Changement de mot de passe",
|
||||||
"clerk" => "",
|
"clerk" => "Employé",
|
||||||
"commission" => "",
|
"commission" => "Commission",
|
||||||
"confirm_delete" => "Êtes-vous certain de vouloir supprimer le(s) employé(s) sélectionné(s) ?",
|
"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) ?",
|
"confirm_restore" => "Êtes-vous certain de vouloir restaurer le(s) employé(s) selectionné(s) ?",
|
||||||
"current_password" => "Mot de passe actuel",
|
"current_password" => "Mot de passe actuel",
|
||||||
"current_password_invalid" => "Le mot de passe actuel est invalide.",
|
"current_password_invalid" => "Le mot de passe actuel est invalide.",
|
||||||
"employee" => "Employé",
|
"employee" => "Employé",
|
||||||
"error_adding_updating" => "Erreur d'ajout/édition d'employé.",
|
"error_adding_updating" => "Erreur d'ajout/édition d'employé.",
|
||||||
|
"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_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.",
|
"error_updating_demo_admin" => "Vous ne pouvez pas modifier l'utilisateur de démonstration admin.",
|
||||||
"language" => "Langue",
|
"language" => "Langue",
|
||||||
"login_info" => "Connexion",
|
"login_info" => "Connexion",
|
||||||
"manager" => "",
|
"manager" => "Gestionnaire",
|
||||||
"new" => "Nouvel employé",
|
"new" => "Nouvel employé",
|
||||||
"none_selected" => "Aucun employé sélectionné pour la suppression.",
|
"none_selected" => "Aucun employé sélectionné pour la suppression.",
|
||||||
"one_or_multiple" => "employé(s)",
|
"one_or_multiple" => "employé(s)",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "Le prix de gros est requis.",
|
"cost_price_required" => "Le prix de gros est requis.",
|
||||||
"count" => "Mise à jour de l'inventaire",
|
"count" => "Mise à jour de l'inventaire",
|
||||||
"csv_import_failed" => "Échec d'import CSV",
|
"csv_import_failed" => "Échec d'import CSV",
|
||||||
|
"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_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_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.",
|
"csv_import_success" => "Importation des articles réussie.",
|
||||||
|
|||||||
@@ -146,4 +146,5 @@ return [
|
|||||||
"used" => "Points utilisés",
|
"used" => "Points utilisés",
|
||||||
"work_orders" => "Ordre Du Travail",
|
"work_orders" => "Ordre Du Travail",
|
||||||
"zero_and_less" => "Zéro ou moin",
|
"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_number_duplicate" => "Le numéro de bon de travail doit être unique.",
|
||||||
"work_order_sent" => "Ordre de travail envoyé à",
|
"work_order_sent" => "Ordre de travail envoyé à",
|
||||||
"work_order_unsent" => "L'ordre de travail n'a pas pu être 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_delete" => "האם אתה בטוח שברצונך למחוק את המאפיינים שנבחרו?",
|
||||||
"confirm_restore" => "האם אתה בטוח שברצונך לשחזר את המאפיינים שנבחרו?",
|
"confirm_restore" => "האם אתה בטוח שברצונך לשחזר את המאפיינים שנבחרו?",
|
||||||
"definition_cannot_be_deleted" => "לא ניתן למחוק מאפיינים נבחר(ים)",
|
"definition_cannot_be_deleted" => "לא ניתן למחוק מאפיינים נבחר(ים)",
|
||||||
|
"definition_invalid_group" => "הקבוצה שנבחרה לא קיימת או אינה תקינה.",
|
||||||
"definition_error_adding_updating" => "לא ניתן להוסיף או לעדכן את הערך {0}. בדוק את יומן השגיאות.",
|
"definition_error_adding_updating" => "לא ניתן להוסיף או לעדכן את הערך {0}. בדוק את יומן השגיאות.",
|
||||||
"definition_flags" => "מאפיין גלוי",
|
"definition_flags" => "מאפיין גלוי",
|
||||||
"definition_group" => "קבוצה",
|
"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" => "דצמבר",
|
||||||
|
];
|
||||||
@@ -14,6 +14,8 @@ return [
|
|||||||
"current_password_invalid" => "הסיסמה הנוכחית אינה חוקית.",
|
"current_password_invalid" => "הסיסמה הנוכחית אינה חוקית.",
|
||||||
"employee" => "עובד",
|
"employee" => "עובד",
|
||||||
"error_adding_updating" => "הוספה או עדכון של עובד נכשלה.",
|
"error_adding_updating" => "הוספה או עדכון של עובד נכשלה.",
|
||||||
|
"error_deleting_admin" => "",
|
||||||
|
"error_updating_admin" => "",
|
||||||
"error_deleting_demo_admin" => "לא ניתן למחוק את משתמש המנהל ההדגמה.",
|
"error_deleting_demo_admin" => "לא ניתן למחוק את משתמש המנהל ההדגמה.",
|
||||||
"error_updating_demo_admin" => "לא ניתן לשנות את משתמש המנהל ההדגמה.",
|
"error_updating_demo_admin" => "לא ניתן לשנות את משתמש המנהל ההדגמה.",
|
||||||
"language" => "שפה",
|
"language" => "שפה",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ return [
|
|||||||
"cost_price_required" => "מחיר סיטונאי הינו שדה חובה.",
|
"cost_price_required" => "מחיר סיטונאי הינו שדה חובה.",
|
||||||
"count" => "עדכן מלאי",
|
"count" => "עדכן מלאי",
|
||||||
"csv_import_failed" => "ייבוא אקסל נכשל",
|
"csv_import_failed" => "ייבוא אקסל נכשל",
|
||||||
|
"csv_import_invalid_location" => "",
|
||||||
"csv_import_nodata_wrongformat" => "בקובץ שהועלה אין נתונים או פורמט שגוי.",
|
"csv_import_nodata_wrongformat" => "בקובץ שהועלה אין נתונים או פורמט שגוי.",
|
||||||
"csv_import_partially_failed" => "ייבוא פריט הצליח עם מספר שגיאות:",
|
"csv_import_partially_failed" => "ייבוא פריט הצליח עם מספר שגיאות:",
|
||||||
"csv_import_success" => "ייבוא הפריט הצליח.",
|
"csv_import_success" => "ייבוא הפריט הצליח.",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user