mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-28 04:01:10 -04:00
Compare commits
258 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b03bc798e | |||
| 482556d378 | |||
| deb525af6e | |||
| cb2bfbb91c | |||
| 654395a175 | |||
| e31b60bc48 | |||
| 183953f4c4 | |||
| a24d8d3ebc | |||
| 4ca574c581 | |||
| c7ce8c87dd | |||
| f64d546672 | |||
| d4a1f1a784 | |||
| e07532961e | |||
| 450c265ded | |||
| f8502c3ca8 | |||
| 899da6990d | |||
| e7675f938e | |||
| b08138e9e0 | |||
| 5df4abdc4b | |||
| a2fa8afa72 | |||
| 7670cd67dc | |||
| 8446ac2b27 | |||
| 63a80e44d5 | |||
| 076df75322 | |||
| 11db99da73 | |||
| 050dca5a50 | |||
| 3c096f1386 | |||
| 0f3e8fce3b | |||
| 325f90bba5 | |||
| a739a938fc | |||
| b30e3a9b11 | |||
| fc1a7c7438 | |||
| 6046113cb1 | |||
| 611ffafec5 | |||
| c497b906df | |||
| c68fce19f9 | |||
| f8913531b6 | |||
| 30f76e2088 | |||
| 39556892cd | |||
| 2fd66bf748 | |||
| d4f1428d5f | |||
| 189141c84d | |||
| f8ccfece09 | |||
| 9a7c926d53 | |||
| c5c1674153 | |||
| 8562ee5414 | |||
| 06c66a756c | |||
| b66d07d21b | |||
| 05001b6a79 | |||
| f02f4ba9d3 | |||
| fbace98aac | |||
| 8f0af3dcd6 | |||
| e8e44c5dc8 | |||
| ac33164342 | |||
| 5c7c0d84ea | |||
| 7ca725ac37 | |||
| 510a4b3dbb | |||
| 0f130ab1b8 | |||
| 25114009e3 | |||
| 79c16d74ce | |||
| 742e1e445a | |||
| 386f96d60e | |||
| 82d85af672 | |||
| 4d1b267688 | |||
| bc99ad63a6 | |||
| 4bb44f8c93 | |||
| c72265ed50 | |||
| b8958c9eb6 | |||
| e33e314cb7 | |||
| 84cebee9da | |||
| 34d3cf7ae8 | |||
| 93d0da836a | |||
| fd51276948 | |||
| d6274854ba | |||
| ea4bd1a31d | |||
| 286e047963 | |||
| be16f48f3d | |||
| ebea1e0813 | |||
| cc8d08f829 | |||
| aacffc22eb | |||
| d71ca4ffb9 | |||
| 186004f7f8 | |||
| c2eb22d666 | |||
| af189b15b6 | |||
| 1c19be85c3 | |||
| 4bb4362d23 | |||
| f6f66b3ae6 | |||
| b4ccecbcf1 | |||
| 92f1f196bb | |||
| ee14070a7b | |||
| 8ce7e14a02 | |||
| 3401ca049e | |||
| 5dcc7b9efd | |||
| 06a538bb81 | |||
| 7ab0419f27 | |||
| a7275aaa42 | |||
| bc4e6a05ea | |||
| ca170f5a87 | |||
| 22e7e96dfa | |||
| fcfd1ddb7a | |||
| daf8c9265b | |||
| 406d098172 | |||
| 824d2e3e8d | |||
| 3cd975dbbd | |||
| 8e50c36a71 | |||
| b499741ab4 | |||
| b409cdb913 | |||
| 13e56105e3 | |||
| f68e86e4cf | |||
| da996c1f33 | |||
| 0990ce4678 | |||
| bb6fb2f49d | |||
| 400296575e | |||
| d58c790b1f | |||
| c674c2ab9e | |||
| d79692cf3b | |||
| 353c2479f1 | |||
| 0176a854b8 | |||
| 00548ea908 | |||
| 09e335a8a7 | |||
| 53e2ed253f | |||
| 06b035d9ac | |||
| 5c88cbcc42 | |||
| d9b175a676 | |||
| f5b9bc95c6 | |||
| 586dcdea0d | |||
| 50957fc179 | |||
| c725e4744b | |||
| 7479ce237e | |||
| 84420441c0 | |||
| ac96721e87 | |||
| db4c7f5e32 | |||
| 87dc78eea0 | |||
| e9c2898056 | |||
| b9c4570137 | |||
| 8e2525cc6c | |||
| 8862a93f23 | |||
| 82efd88920 | |||
| 0ef528d296 | |||
| 4c33a5d88c | |||
| d64d06181b | |||
| ef9cf2db22 | |||
| 96c295a003 | |||
| 22528f5b66 | |||
| 1cd9c72537 | |||
| 7253b43eb4 | |||
| 181964cf03 | |||
| 5914245ae4 | |||
| 1bf3d28d4e | |||
| dbcbd93ace | |||
| 1729c6a308 | |||
| 019493cbfa | |||
| 60540ba966 | |||
| 601ad419ec | |||
| 80e7bab891 | |||
| f5c8befbf0 | |||
| 09c984baa7 | |||
| 0d93260672 | |||
| 3e9e217f92 | |||
| 3cd8859c62 | |||
| 4493b4a419 | |||
| 79e3e70bd6 | |||
| 56a955befd | |||
| 496c28f80d | |||
| 7a59f3fe0c | |||
| 3d6875a532 | |||
| 15bf380f4f | |||
| 0b910db039 | |||
| 0e5e8f602f | |||
| d9db0f9401 | |||
| c0da7c7339 | |||
| 7e7599b4a7 | |||
| 99cd88e6c6 | |||
| 053a06229c | |||
| 1a6e8280a8 | |||
| 125e8be83c | |||
| 4d89ca2101 | |||
| e8aee3bb32 | |||
| d3c7ca75f0 | |||
| 694d5f56d5 | |||
| a48439785c | |||
| 7c9bd84f00 | |||
| bd5a93d81c | |||
| 858e10953b | |||
| 3617032735 | |||
| 75ddc51b1e | |||
| 1dfa36e396 | |||
| d9e9a5a540 | |||
| ea6e11c324 | |||
| f55dfe0b46 | |||
| 3eac3b8af5 | |||
| 2b2bd4351a | |||
| b9c32bbdc1 | |||
| bceffbf6a0 | |||
| 7c6a40374d | |||
| d04e142a3e | |||
| f11436736b | |||
| 9271ceba45 | |||
| c88eb24265 | |||
| 5eb0a04378 | |||
| d926073095 | |||
| a691969025 | |||
| 7df06fb005 | |||
| 45db850025 | |||
| 18a50315ba | |||
| bce1b4bb3e | |||
| ddd204105f | |||
| e030d4b9d0 | |||
| 302968225a | |||
| e59bf288ce | |||
| b1fcd90b62 | |||
| ddb0ff1b8a | |||
| ce99fa3d82 | |||
| e28c89085d | |||
| 34f7e33abc | |||
| 80be7a492d | |||
| 387cb4490d | |||
| 09829a559e | |||
| b06fc5f0b9 | |||
| 5f7401f622 | |||
| 4f6dae919b | |||
| 36be395579 | |||
| 79e77f9e16 | |||
| cbf0af2120 | |||
| 92f754e888 | |||
| a6896eaa01 | |||
| 01f3646869 | |||
| b2918e9dbb | |||
| 0a064ec5ba | |||
| 5f0b4b3496 | |||
| 17b59f0d19 | |||
| 283b910cc3 | |||
| 81739827c0 | |||
| 90edc3a85e | |||
| 655c2a7849 | |||
| ca833d174e | |||
| 33e8381fc4 | |||
| 9b5125d440 | |||
| 2899021804 | |||
| d8f6d03d1e | |||
| c474e98925 | |||
| 799d212d9b | |||
| 9424dc6c27 | |||
| fa15502ce7 | |||
| 1f4d3bf784 | |||
| 3692373cd2 | |||
| 0c71356f59 | |||
| e539bb501d | |||
| 2fcd169270 | |||
| 14d71fedb3 | |||
| 7fe9a4c2a2 | |||
| 7b697a477e | |||
| 146cf835b9 | |||
| ec87e72547 | |||
| bf2e8c9c99 | |||
| b6096aadfa | |||
| 1cbc41c3ce | |||
| 8bc5ea2d5e |
10
.dockerignore
Normal file
10
.dockerignore
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.dockerignore
|
||||||
|
.gitignore
|
||||||
|
*.md
|
||||||
|
.git/
|
||||||
|
.idea/
|
||||||
|
.DS_Store/
|
||||||
|
docker-compose.*
|
||||||
|
LICENSE
|
||||||
|
nginx.conf
|
||||||
|
yarn.lock
|
||||||
@ -1,15 +1,15 @@
|
|||||||
APP_ENV=production
|
APP_ENV=production
|
||||||
APP_KEY=base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0=
|
APP_KEY=base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0=
|
||||||
APP_DEBUG=false
|
APP_DEBUG=true
|
||||||
APP_LOG_LEVEL=debug
|
APP_LOG_LEVEL=debug
|
||||||
APP_URL=http://crater.test
|
APP_URL=http://crater.test
|
||||||
|
|
||||||
DB_CONNECTION=mysql
|
DB_CONNECTION=mysql
|
||||||
DB_HOST=127.0.0.1
|
DB_HOST=db
|
||||||
DB_PORT=3306
|
DB_PORT=3306
|
||||||
DB_DATABASE=crater
|
DB_DATABASE=crater
|
||||||
DB_USERNAME=root
|
DB_USERNAME=crater
|
||||||
DB_PASSWORD=bytefury
|
DB_PASSWORD="crater"
|
||||||
|
|
||||||
BROADCAST_DRIVER=log
|
BROADCAST_DRIVER=log
|
||||||
CACHE_DRIVER=file
|
CACHE_DRIVER=file
|
||||||
|
|||||||
12
.eslintrc
12
.eslintrc
@ -2,9 +2,17 @@
|
|||||||
"root": true,
|
"root": true,
|
||||||
"extends": [
|
"extends": [
|
||||||
"plugin:vue/recommended",
|
"plugin:vue/recommended",
|
||||||
"standard"
|
"eslint:recommended",
|
||||||
|
"prettier/vue",
|
||||||
|
"plugin:prettier/recommended"
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"vue/max-attributes-per-line" : 3
|
"vue/max-attributes-per-line": ["error", {
|
||||||
|
"singleline": 10,
|
||||||
|
"multiline": {
|
||||||
|
"max": 1,
|
||||||
|
"allowFirstLine": false
|
||||||
|
}
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
26
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
26
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Please complete the following information:**
|
||||||
|
- Crater version:
|
||||||
|
- PHP version:
|
||||||
|
- Database type and version:
|
||||||
|
|
||||||
|
**Optional info**
|
||||||
|
- OS: [e.g. Ubuntu]
|
||||||
|
- Browser: [e.g. chrome, safari]
|
||||||
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -11,3 +11,5 @@ Homestead.yaml
|
|||||||
.rnd
|
.rnd
|
||||||
/.expo
|
/.expo
|
||||||
/.vscode
|
/.vscode
|
||||||
|
docker-compose.yml
|
||||||
|
docker-compose.yaml
|
||||||
|
|||||||
5
.prettierrc.json
Normal file
5
.prettierrc.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"tabWidth": 2
|
||||||
|
}
|
||||||
53
Dockerfile
Normal file
53
Dockerfile
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
##### STAGE 1 #####
|
||||||
|
|
||||||
|
FROM composer as composer
|
||||||
|
|
||||||
|
# Copy composer files from project root into composer container's working dir
|
||||||
|
COPY composer.* /app/
|
||||||
|
|
||||||
|
# Copy database directory for autoloader optimization
|
||||||
|
COPY database /app/database
|
||||||
|
|
||||||
|
# Run composer to build dependencies in vendor folder
|
||||||
|
RUN composer install --no-scripts --no-suggest --no-interaction --prefer-dist --optimize-autoloader
|
||||||
|
|
||||||
|
# Copy everything from project root into composer container's working dir
|
||||||
|
COPY . /app
|
||||||
|
|
||||||
|
RUN composer dump-autoload --optimize --classmap-authoritative
|
||||||
|
|
||||||
|
##### STAGE 2 #####
|
||||||
|
|
||||||
|
FROM php:7.3.12-fpm-alpine
|
||||||
|
|
||||||
|
# Use the default production configuration
|
||||||
|
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
||||||
|
|
||||||
|
RUN apk add --no-cache libpng-dev libxml2-dev oniguruma-dev libzip-dev gnu-libiconv && \
|
||||||
|
docker-php-ext-install bcmath ctype json gd mbstring pdo pdo_mysql tokenizer xml zip
|
||||||
|
|
||||||
|
ENV LD_PRELOAD /usr/lib/preloadable_libiconv.so php
|
||||||
|
|
||||||
|
# Set container's working dir
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy everything from project root into php container's working dir
|
||||||
|
COPY . /app
|
||||||
|
|
||||||
|
# Copy vendor folder from composer container into php container
|
||||||
|
COPY --from=composer /app/vendor /app/vendor
|
||||||
|
|
||||||
|
RUN touch database/database.sqlite && \
|
||||||
|
cp .env.example .env && \
|
||||||
|
php artisan config:cache && \
|
||||||
|
php artisan passport:keys && \
|
||||||
|
php artisan key:generate && \
|
||||||
|
chown -R www-data:www-data . && \
|
||||||
|
chmod -R 755 . && \
|
||||||
|
chmod -R 775 storage/framework/ && \
|
||||||
|
chmod -R 775 storage/logs/ && \
|
||||||
|
chmod -R 775 bootstrap/cache/
|
||||||
|
|
||||||
|
EXPOSE 9000
|
||||||
|
|
||||||
|
CMD ["php-fpm", "--nodaemonize"]
|
||||||
@ -7,8 +7,8 @@ use Crater\Country;
|
|||||||
|
|
||||||
class Address extends Model
|
class Address extends Model
|
||||||
{
|
{
|
||||||
const BILLING_TYPE = 'BILLING';
|
const BILLING_TYPE = 'billing';
|
||||||
const SHIPPING_TYPE = 'SHIPPING';
|
const SHIPPING_TYPE = 'shipping';
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'name',
|
'name',
|
||||||
|
|||||||
51
app/Console/Commands/ResetApp.php
Normal file
51
app/Console/Commands/ResetApp.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
use Illuminate\Filesystem\Filesystem;
|
||||||
|
|
||||||
|
class ResetApp extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'reset:app';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Clean database, database_created and public/storage folder';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
if ($this->confirm('Do you wish to continue? This will delete your tables')) {
|
||||||
|
Artisan::call('migrate:reset --force');
|
||||||
|
|
||||||
|
\Storage::disk('local')->delete('database_created');
|
||||||
|
|
||||||
|
// $file = new Filesystem;
|
||||||
|
// $file->cleanDirectory('public/storage');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
189
app/Console/Commands/UpdateCommand.php
Normal file
189
app/Console/Commands/UpdateCommand.php
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Crater\Space\Updater;
|
||||||
|
use Crater\Setting;
|
||||||
|
|
||||||
|
class UpdateCommand extends Command
|
||||||
|
{
|
||||||
|
public $installed;
|
||||||
|
|
||||||
|
public $version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'crater:update';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Automatically update your crater app';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
set_time_limit(3600); // 1 hour
|
||||||
|
|
||||||
|
$this->installed = $this->getInstalledVersion();
|
||||||
|
$this->version = $this->getLatestVersion();
|
||||||
|
|
||||||
|
if (!$this->version) {
|
||||||
|
$this->info('No Update Available! You are already on the latest version.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->confirm("Do you wish to update to {$this->version}?")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$path = $this->download()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$path = $this->unzip($path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->copyFiles($path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->migrateUpdate()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->finish()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info('Successfully updated to ' . $this->version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInstalledVersion()
|
||||||
|
{
|
||||||
|
return Setting::getSetting('version');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLatestVersion()
|
||||||
|
{
|
||||||
|
$this->info('Your currently installed version is ' . $this->installed);
|
||||||
|
$this->line('');
|
||||||
|
$this->info('Checking for update...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = Updater::checkForUpdate($this->installed);
|
||||||
|
|
||||||
|
if ($response->success) {
|
||||||
|
return $response->version->version;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error($e->getMessage());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function download()
|
||||||
|
{
|
||||||
|
$this->info('Downloading update...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$path = Updater::download($this->version);
|
||||||
|
if (!is_string($path)) {
|
||||||
|
$this->error('Download exception');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error($e->getMessage());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unzip($path)
|
||||||
|
{
|
||||||
|
$this->info('Unzipping update package...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$path = Updater::unzip($path);
|
||||||
|
if (!is_string($path)) {
|
||||||
|
$this->error('Unzipping exception');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error($e->getMessage());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function copyFiles($path)
|
||||||
|
{
|
||||||
|
$this->info('Copying update files...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
Updater::copyFiles($path);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error($e->getMessage());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function migrateUpdate()
|
||||||
|
{
|
||||||
|
$this->info('Running Migrations...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
Updater::migrateUpdate();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error($e->getMessage());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function finish()
|
||||||
|
{
|
||||||
|
$this->info('Finishing update...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
Updater::finishUpdate($this->installed, $this->version);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error($e->getMessage());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,7 +12,8 @@ class Kernel extends ConsoleKernel
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $commands = [
|
protected $commands = [
|
||||||
|
Commands\ResetApp::class,
|
||||||
|
Commands\UpdateCommand::class
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -49,15 +49,20 @@ class Estimate extends Model
|
|||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'total' => 'float',
|
'total' => 'integer',
|
||||||
'tax' => 'float',
|
'tax' => 'integer',
|
||||||
'sub_total' => 'float'
|
'sub_total' => 'integer',
|
||||||
|
'discount' => 'float',
|
||||||
|
'discount_val' => 'integer',
|
||||||
];
|
];
|
||||||
|
|
||||||
public static function getNextEstimateNumber()
|
public static function getNextEstimateNumber($value)
|
||||||
{
|
{
|
||||||
// Get the last created order
|
// Get the last created order
|
||||||
$lastOrder = Estimate::orderBy('created_at', 'desc')->first();
|
$lastOrder = Estimate::where('estimate_number', 'LIKE', $value . '-%')
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->first();
|
||||||
|
|
||||||
if (!$lastOrder) {
|
if (!$lastOrder) {
|
||||||
// We get here if there is no order at all
|
// We get here if there is no order at all
|
||||||
// If there is no number set it to 0, which will be 1 at the end.
|
// If there is no number set it to 0, which will be 1 at the end.
|
||||||
@ -99,10 +104,16 @@ class Estimate extends Model
|
|||||||
|
|
||||||
public function getEstimateNumAttribute()
|
public function getEstimateNumAttribute()
|
||||||
{
|
{
|
||||||
$position = $this->strposX($this->estimate_number, "-", 2) + 1;
|
$position = $this->strposX($this->estimate_number, "-", 1) + 1;
|
||||||
return substr($this->estimate_number, $position);
|
return substr($this->estimate_number, $position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getEstimatePrefixAttribute()
|
||||||
|
{
|
||||||
|
$prefix = explode("-",$this->estimate_number)[0];
|
||||||
|
return $prefix;
|
||||||
|
}
|
||||||
|
|
||||||
private function strposX($haystack, $needle, $number)
|
private function strposX($haystack, $needle, $number)
|
||||||
{
|
{
|
||||||
if ($number == '1') {
|
if ($number == '1') {
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
use Spatie\MediaLibrary\HasMedia\HasMedia;
|
use Spatie\MediaLibrary\HasMedia\HasMedia;
|
||||||
use Spatie\MediaLibrary\HasMedia\HasMediaTrait;
|
use Spatie\MediaLibrary\HasMedia\HasMediaTrait;
|
||||||
use Crater\ExpenseCategory;
|
use Crater\ExpenseCategory;
|
||||||
|
use Crater\User;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ class Expense extends Model implements HasMedia
|
|||||||
'expense_category_id',
|
'expense_category_id',
|
||||||
'amount',
|
'amount',
|
||||||
'company_id',
|
'company_id',
|
||||||
|
'user_id',
|
||||||
'expense_date',
|
'expense_date',
|
||||||
'notes',
|
'notes',
|
||||||
'attachment_receipt'
|
'attachment_receipt'
|
||||||
@ -32,6 +34,11 @@ class Expense extends Model implements HasMedia
|
|||||||
return $this->belongsTo(ExpenseCategory::class, 'expense_category_id');
|
return $this->belongsTo(ExpenseCategory::class, 'expense_category_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function getFormattedExpenseDateAttribute($value)
|
public function getFormattedExpenseDateAttribute($value)
|
||||||
{
|
{
|
||||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id);
|
$dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id);
|
||||||
@ -81,6 +88,11 @@ class Expense extends Model implements HasMedia
|
|||||||
return $query->where('expenses.expense_category_id', $categoryId);
|
return $query->where('expenses.expense_category_id', $categoryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function scopeWhereUser($query, $user_id)
|
||||||
|
{
|
||||||
|
return $query->where('expenses.user_id', $user_id);
|
||||||
|
}
|
||||||
|
|
||||||
public function scopeApplyFilters($query, array $filters)
|
public function scopeApplyFilters($query, array $filters)
|
||||||
{
|
{
|
||||||
$filters = collect($filters);
|
$filters = collect($filters);
|
||||||
@ -89,6 +101,10 @@ class Expense extends Model implements HasMedia
|
|||||||
$query->whereCategory($filters->get('expense_category_id'));
|
$query->whereCategory($filters->get('expense_category_id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($filters->get('user_id')) {
|
||||||
|
$query->whereUser($filters->get('user_id'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($filters->get('from_date') && $filters->get('to_date')) {
|
if ($filters->get('from_date') && $filters->get('to_date')) {
|
||||||
$start = Carbon::createFromFormat('d/m/Y', $filters->get('from_date'));
|
$start = Carbon::createFromFormat('d/m/Y', $filters->get('from_date'));
|
||||||
$end = Carbon::createFromFormat('d/m/Y', $filters->get('to_date'));
|
$end = Carbon::createFromFormat('d/m/Y', $filters->get('to_date'));
|
||||||
|
|||||||
@ -20,11 +20,22 @@ use Crater\CompanySetting;
|
|||||||
|
|
||||||
class CompanyController extends Controller
|
class CompanyController extends Controller
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Retrive the Admin account.
|
||||||
|
* @return \Crater\User
|
||||||
|
*/
|
||||||
public function getAdmin()
|
public function getAdmin()
|
||||||
{
|
{
|
||||||
return User::find(1);
|
return User::find(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the Admin profile.
|
||||||
|
* Includes name, email and (or) password
|
||||||
|
*
|
||||||
|
* @param \Crater\Http\Requests\ProfileRequest $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function updateAdminProfile(ProfileRequest $request)
|
public function updateAdminProfile(ProfileRequest $request)
|
||||||
{
|
{
|
||||||
$verifyEmail = User::where('email', $request->email)->first();
|
$verifyEmail = User::where('email', $request->email)->first();
|
||||||
@ -54,6 +65,14 @@ class CompanyController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Admin Account alongside the country from the addresses table and
|
||||||
|
* The company from companies table
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function getAdminCompany()
|
public function getAdminCompany()
|
||||||
{
|
{
|
||||||
$user = User::with(['addresses', 'addresses.country', 'company'])->find(1);
|
$user = User::with(['addresses', 'addresses.country', 'company'])->find(1);
|
||||||
@ -63,6 +82,13 @@ class CompanyController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update Admin Company Details
|
||||||
|
* @param \Crater\Http\Requests\CompanyRequest $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function updateAdminCompany(CompanyRequest $request)
|
public function updateAdminCompany(CompanyRequest $request)
|
||||||
{
|
{
|
||||||
$user = User::find(1);
|
$user = User::find(1);
|
||||||
@ -85,6 +111,11 @@ class CompanyController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve General App Settings
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function getGeneralSettings(Request $request)
|
public function getGeneralSettings(Request $request)
|
||||||
{
|
{
|
||||||
$date_formats = DateFormatter::get_list();
|
$date_formats = DateFormatter::get_list();
|
||||||
@ -112,10 +143,14 @@ class CompanyController extends Controller
|
|||||||
$currency = CompanySetting::getSetting('currency', $request->header('company'));
|
$currency = CompanySetting::getSetting('currency', $request->header('company'));
|
||||||
$fiscal_year = CompanySetting::getSetting('fiscal_year', $request->header('company'));
|
$fiscal_year = CompanySetting::getSetting('fiscal_year', $request->header('company'));
|
||||||
|
|
||||||
$languages = [
|
$languages = [ // alphabetical order
|
||||||
|
["code"=>"pt_BR", "name" => "Brazilian Portuguese"],
|
||||||
["code"=>"en", "name" => "English"],
|
["code"=>"en", "name" => "English"],
|
||||||
["code"=>"fr", "name" => "French"],
|
["code"=>"fr", "name" => "French"],
|
||||||
["code"=>"es", "name" => "Spanish"]
|
["code"=>"de", "name" => "German"],
|
||||||
|
["code"=>"it", "name" => "Italian"],
|
||||||
|
["code"=>"es", "name" => "Spanish"],
|
||||||
|
["code"=>"ar", "name" => "العربية"],
|
||||||
];
|
];
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
@ -133,6 +168,13 @@ class CompanyController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update General App Settings
|
||||||
|
* @param \Crater\Http\Requests\CompanySettingRequest $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function updateGeneralSettings(CompanySettingRequest $request)
|
public function updateGeneralSettings(CompanySettingRequest $request)
|
||||||
{
|
{
|
||||||
$sets = [
|
$sets = [
|
||||||
@ -153,6 +195,63 @@ class CompanyController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCustomizeSetting (Request $request)
|
||||||
|
{
|
||||||
|
$invoice_prefix = CompanySetting::getSetting('invoice_prefix', $request->header('company'));
|
||||||
|
$invoice_auto_generate = CompanySetting::getSetting('invoice_auto_generate', $request->header('company'));
|
||||||
|
|
||||||
|
$estimate_prefix = CompanySetting::getSetting('estimate_prefix', $request->header('company'));
|
||||||
|
$estimate_auto_generate = CompanySetting::getSetting('estimate_auto_generate', $request->header('company'));
|
||||||
|
|
||||||
|
$payment_prefix = CompanySetting::getSetting('payment_prefix', $request->header('company'));
|
||||||
|
$payment_auto_generate = CompanySetting::getSetting('payment_auto_generate', $request->header('company'));
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'invoice_prefix' => $invoice_prefix,
|
||||||
|
'invoice_auto_generate' => $invoice_auto_generate,
|
||||||
|
'estimate_prefix' => $estimate_prefix,
|
||||||
|
'estimate_auto_generate' => $estimate_auto_generate,
|
||||||
|
'payment_prefix' => $payment_prefix,
|
||||||
|
'payment_auto_generate' => $payment_auto_generate,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateCustomizeSetting (Request $request)
|
||||||
|
{
|
||||||
|
$sets = [];
|
||||||
|
|
||||||
|
if ($request->type == "PAYMENTS") {
|
||||||
|
$sets = [
|
||||||
|
'payment_prefix'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->type == "INVOICES") {
|
||||||
|
$sets = [
|
||||||
|
'invoice_prefix',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->type == "ESTIMATES") {
|
||||||
|
$sets = [
|
||||||
|
'estimate_prefix',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($sets as $key) {
|
||||||
|
CompanySetting::setSetting($key, $request->$key, $request->header('company'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a specific Company Setting
|
||||||
|
* @param \Crater\Http\Requests\SettingRequest $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function updateSetting(SettingRequest $request)
|
public function updateSetting(SettingRequest $request)
|
||||||
{
|
{
|
||||||
CompanySetting::setSetting($request->key, $request->value, $request->header('company'));
|
CompanySetting::setSetting($request->key, $request->value, $request->header('company'));
|
||||||
@ -162,6 +261,11 @@ class CompanyController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve Specific Company Setting
|
||||||
|
* @param \Crater\Http\Requests\SettingKeyRequest $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function getSetting(SettingKeyRequest $request)
|
public function getSetting(SettingKeyRequest $request)
|
||||||
{
|
{
|
||||||
$setting = CompanySetting::getSetting($request->key, $request->header('company'));
|
$setting = CompanySetting::getSetting($request->key, $request->header('company'));
|
||||||
@ -171,6 +275,12 @@ class CompanyController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve App Colors
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function getColors(Request $request)
|
public function getColors(Request $request)
|
||||||
{
|
{
|
||||||
$colors = [
|
$colors = [
|
||||||
@ -205,7 +315,7 @@ class CompanyController extends Controller
|
|||||||
* Upload the company logo to storage.
|
* Upload the company logo to storage.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function uploadCompanyLogo(Request $request)
|
public function uploadCompanyLogo(Request $request)
|
||||||
{
|
{
|
||||||
@ -232,7 +342,7 @@ class CompanyController extends Controller
|
|||||||
* Upload the Admin Avatar to public storage.
|
* Upload the Admin Avatar to public storage.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function uploadAdminAvatar(Request $request)
|
public function uploadAdminAvatar(Request $request)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -19,7 +19,7 @@ class CustomersController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
@ -53,7 +53,7 @@ class CustomersController extends Controller
|
|||||||
* Store a newly created resource in storage.
|
* Store a newly created resource in storage.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function store(Requests\CustomerRequest $request)
|
public function store(Requests\CustomerRequest $request)
|
||||||
{
|
{
|
||||||
@ -104,7 +104,7 @@ class CustomersController extends Controller
|
|||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id)
|
||||||
{
|
{
|
||||||
@ -124,7 +124,7 @@ class CustomersController extends Controller
|
|||||||
* Show the form for editing the specified resource.
|
* Show the form for editing the specified resource.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function edit($id)
|
public function edit($id)
|
||||||
{
|
{
|
||||||
@ -144,7 +144,7 @@ class CustomersController extends Controller
|
|||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function update($id, Requests\CustomerRequest $request)
|
public function update($id, Requests\CustomerRequest $request)
|
||||||
{
|
{
|
||||||
@ -177,6 +177,7 @@ class CustomersController extends Controller
|
|||||||
$customer->enable_portal = $request->enable_portal;
|
$customer->enable_portal = $request->enable_portal;
|
||||||
$customer->save();
|
$customer->save();
|
||||||
|
|
||||||
|
$customer->addresses()->delete();
|
||||||
if ($request->addresses) {
|
if ($request->addresses) {
|
||||||
foreach ($request->addresses as $address) {
|
foreach ($request->addresses as $address) {
|
||||||
$newAddress = $customer->addresses()->firstOrNew(['type' => $address["type"]]);
|
$newAddress = $customer->addresses()->firstOrNew(['type' => $address["type"]]);
|
||||||
@ -203,10 +204,10 @@ class CustomersController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the specified resource from storage.
|
* Remove the specified Customer along side all his/her resources (ie. Estimates, Invoices, Payments and Addresses)
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id)
|
||||||
{
|
{
|
||||||
@ -217,6 +218,13 @@ class CustomersController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a list of Customers along side all their resources (ie. Estimates, Invoices, Payments and Addresses)
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function delete(Request $request)
|
public function delete(Request $request)
|
||||||
{
|
{
|
||||||
foreach ($request->id as $id) {
|
foreach ($request->id as $id) {
|
||||||
|
|||||||
@ -15,6 +15,12 @@ use Illuminate\Support\Facades\DB;
|
|||||||
|
|
||||||
class DashboardController extends Controller
|
class DashboardController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve Dashboard details
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$invoiceTotals = [];
|
$invoiceTotals = [];
|
||||||
@ -30,7 +36,8 @@ class DashboardController extends Controller
|
|||||||
$start = Carbon::now();
|
$start = Carbon::now();
|
||||||
$end = Carbon::now();
|
$end = Carbon::now();
|
||||||
$terms = explode('-', $fiscalYear);
|
$terms = explode('-', $fiscalYear);
|
||||||
if ($terms[0] < $start->month) {
|
|
||||||
|
if ($terms[0] <= $start->month) {
|
||||||
$startDate->month($terms[0])->startOfMonth();
|
$startDate->month($terms[0])->startOfMonth();
|
||||||
$start->month($terms[0])->startOfMonth();
|
$start->month($terms[0])->startOfMonth();
|
||||||
$end->month($terms[0])->endOfMonth();
|
$end->month($terms[0])->endOfMonth();
|
||||||
@ -87,6 +94,7 @@ class DashboardController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$start->subMonth()->endOfMonth();
|
$start->subMonth()->endOfMonth();
|
||||||
|
|
||||||
$salesTotal = Invoice::whereCompany($request->header('company'))
|
$salesTotal = Invoice::whereCompany($request->header('company'))
|
||||||
->whereBetween(
|
->whereBetween(
|
||||||
'invoice_date',
|
'invoice_date',
|
||||||
@ -137,6 +145,11 @@ class DashboardController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrive Expense Chart data
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function getExpenseChartData(Request $request)
|
public function getExpenseChartData(Request $request)
|
||||||
{
|
{
|
||||||
$expensesCategories = Expense::with('category')
|
$expensesCategories = Expense::with('category')
|
||||||
|
|||||||
@ -56,25 +56,43 @@ class EstimatesController extends Controller
|
|||||||
|
|
||||||
public function create(Request $request)
|
public function create(Request $request)
|
||||||
{
|
{
|
||||||
$nextEstimateNumber = 'EST-'.Estimate::getNextEstimateNumber();
|
$estimate_prefix = CompanySetting::getSetting('estimate_prefix', $request->header('company'));
|
||||||
|
$estimate_num_auto_generate = CompanySetting::getSetting('estimate_auto_generate', $request->header('company'));
|
||||||
|
|
||||||
|
$nextEstimateNumberAttribute = null;
|
||||||
|
$nextEstimateNumber = Estimate::getNextEstimateNumber($estimate_prefix);
|
||||||
|
|
||||||
|
if ($estimate_num_auto_generate == "YES") {
|
||||||
|
$nextEstimateNumberAttribute = $nextEstimateNumber;
|
||||||
|
}
|
||||||
|
|
||||||
$tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company'));
|
$tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company'));
|
||||||
$discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company'));
|
$discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company'));
|
||||||
$customers = User::where('role', 'customer')->get();
|
$customers = User::where('role', 'customer')->get();
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'customers' => $customers,
|
'customers' => $customers,
|
||||||
'nextEstimateNumber' => $nextEstimateNumber,
|
'nextEstimateNumberAttribute' => $nextEstimateNumberAttribute,
|
||||||
|
'nextEstimateNumber' => $estimate_prefix.'-'.$nextEstimateNumber,
|
||||||
'taxes' => Tax::whereCompany($request->header('company'))->latest()->get(),
|
'taxes' => Tax::whereCompany($request->header('company'))->latest()->get(),
|
||||||
'items' => Item::whereCompany($request->header('company'))->get(),
|
'items' => Item::whereCompany($request->header('company'))->get(),
|
||||||
'tax_per_item' => $tax_per_item,
|
'tax_per_item' => $tax_per_item,
|
||||||
'discount_per_item' => $discount_per_item,
|
'discount_per_item' => $discount_per_item,
|
||||||
'estimateTemplates' => EstimateTemplate::all(),
|
'estimateTemplates' => EstimateTemplate::all(),
|
||||||
'shareable_link' => ''
|
'shareable_link' => '',
|
||||||
|
'estimate_prefix' => $estimate_prefix
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store(EstimatesRequest $request)
|
public function store(EstimatesRequest $request)
|
||||||
{
|
{
|
||||||
|
$estimate_number = explode("-",$request->estimate_number);
|
||||||
|
$number_attributes['estimate_number'] = $estimate_number[0].'-'.sprintf('%06d', intval($estimate_number[1]));
|
||||||
|
|
||||||
|
Validator::make($number_attributes, [
|
||||||
|
'estimate_number' => 'required|unique:estimates,estimate_number'
|
||||||
|
])->validate();
|
||||||
|
|
||||||
$estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date);
|
$estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date);
|
||||||
$expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date);
|
$expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date);
|
||||||
$status = Estimate::STATUS_DRAFT;
|
$status = Estimate::STATUS_DRAFT;
|
||||||
@ -101,7 +119,7 @@ class EstimatesController extends Controller
|
|||||||
$estimate = Estimate::create([
|
$estimate = Estimate::create([
|
||||||
'estimate_date' => $estimate_date,
|
'estimate_date' => $estimate_date,
|
||||||
'expiry_date' => $expiry_date,
|
'expiry_date' => $expiry_date,
|
||||||
'estimate_number' => $request->estimate_number,
|
'estimate_number' => $number_attributes['estimate_number'],
|
||||||
'reference_number' => $request->reference_number,
|
'reference_number' => $request->reference_number,
|
||||||
'user_id' => $request->user_id,
|
'user_id' => $request->user_id,
|
||||||
'company_id' => $request->header('company'),
|
'company_id' => $request->header('company'),
|
||||||
@ -127,7 +145,7 @@ class EstimatesController extends Controller
|
|||||||
|
|
||||||
if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) {
|
if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) {
|
||||||
foreach ($estimateItem['taxes'] as $tax) {
|
foreach ($estimateItem['taxes'] as $tax) {
|
||||||
if ($tax['amount']) {
|
if (gettype($tax['amount']) !== "NULL") {
|
||||||
$tax['company_id'] = $request->header('company');
|
$tax['company_id'] = $request->header('company');
|
||||||
$item->taxes()->create($tax);
|
$item->taxes()->create($tax);
|
||||||
}
|
}
|
||||||
@ -137,7 +155,7 @@ class EstimatesController extends Controller
|
|||||||
|
|
||||||
if ($request->has('taxes')) {
|
if ($request->has('taxes')) {
|
||||||
foreach ($request->taxes as $tax) {
|
foreach ($request->taxes as $tax) {
|
||||||
if ($tax['amount']) {
|
if (gettype($tax['amount']) !== "NULL") {
|
||||||
$tax['company_id'] = $request->header('company');
|
$tax['company_id'] = $request->header('company');
|
||||||
$estimate->taxes()->create($tax);
|
$estimate->taxes()->create($tax);
|
||||||
}
|
}
|
||||||
@ -150,10 +168,6 @@ class EstimatesController extends Controller
|
|||||||
$data['user'] = User::find($userId)->toArray();
|
$data['user'] = User::find($userId)->toArray();
|
||||||
$data['company'] = Company::find($estimate->company_id);
|
$data['company'] = Company::find($estimate->company_id);
|
||||||
$email = $data['user']['email'];
|
$email = $data['user']['email'];
|
||||||
$notificationEmail = CompanySetting::getSetting(
|
|
||||||
'notification_email',
|
|
||||||
$request->header('company')
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$email) {
|
if (!$email) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
@ -161,13 +175,7 @@ class EstimatesController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$notificationEmail) {
|
\Mail::to($email)->send(new EstimatePdf($data));
|
||||||
return response()->json([
|
|
||||||
'error' => 'notification_email_does_not_exist'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
\Mail::to($email)->send(new EstimatePdf($data, $notificationEmail));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$estimate = Estimate::with([
|
$estimate = Estimate::with([
|
||||||
@ -216,26 +224,33 @@ class EstimatesController extends Controller
|
|||||||
|
|
||||||
return response()->json( [
|
return response()->json( [
|
||||||
'customers' => $customers,
|
'customers' => $customers,
|
||||||
'nextEstimateNumber' => $estimate->estimate_number,
|
'nextEstimateNumber' => $estimate->getEstimateNumAttribute(),
|
||||||
'taxes' => Tax::latest()->whereCompany($request->header('company'))->get(),
|
'taxes' => Tax::latest()->whereCompany($request->header('company'))->get(),
|
||||||
'estimate' => $estimate,
|
'estimate' => $estimate,
|
||||||
'items' => Item::whereCompany($request->header('company'))->latest()->get(),
|
'items' => Item::whereCompany($request->header('company'))->latest()->get(),
|
||||||
'estimateTemplates' => EstimateTemplate::all(),
|
'estimateTemplates' => EstimateTemplate::all(),
|
||||||
'tax_per_item' => $estimate->tax_per_item,
|
'tax_per_item' => $estimate->tax_per_item,
|
||||||
'discount_per_item' => $estimate->discount_per_item,
|
'discount_per_item' => $estimate->discount_per_item,
|
||||||
'shareable_link' => url('/estimates/pdf/'.$estimate->unique_hash)
|
'shareable_link' => url('/estimates/pdf/'.$estimate->unique_hash),
|
||||||
|
'estimate_prefix' => $estimate->getEstimatePrefixAttribute()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(EstimatesRequest $request, $id)
|
public function update(EstimatesRequest $request, $id)
|
||||||
{
|
{
|
||||||
|
$estimate_number = explode("-",$request->estimate_number);
|
||||||
|
$number_attributes['estimate_number'] = $estimate_number[0].'-'.sprintf('%06d', intval($estimate_number[1]));
|
||||||
|
Validator::make($number_attributes, [
|
||||||
|
'estimate_number' => 'required|unique:estimates,estimate_number'.','.$id
|
||||||
|
])->validate();
|
||||||
|
|
||||||
$estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date);
|
$estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date);
|
||||||
$expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date);
|
$expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date);
|
||||||
|
|
||||||
$estimate = Estimate::find($id);
|
$estimate = Estimate::find($id);
|
||||||
$estimate->estimate_date = $estimate_date;
|
$estimate->estimate_date = $estimate_date;
|
||||||
$estimate->expiry_date = $expiry_date;
|
$estimate->expiry_date = $expiry_date;
|
||||||
$estimate->estimate_number = $request->estimate_number;
|
$estimate->estimate_number = $number_attributes['estimate_number'];
|
||||||
$estimate->reference_number = $request->reference_number;
|
$estimate->reference_number = $request->reference_number;
|
||||||
$estimate->user_id = $request->user_id;
|
$estimate->user_id = $request->user_id;
|
||||||
$estimate->estimate_template_id = $request->estimate_template_id;
|
$estimate->estimate_template_id = $request->estimate_template_id;
|
||||||
@ -266,7 +281,7 @@ class EstimatesController extends Controller
|
|||||||
|
|
||||||
if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) {
|
if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) {
|
||||||
foreach ($estimateItem['taxes'] as $tax) {
|
foreach ($estimateItem['taxes'] as $tax) {
|
||||||
if ($tax['amount']) {
|
if (gettype($tax['amount']) !== "NULL") {
|
||||||
$tax['company_id'] = $request->header('company');
|
$tax['company_id'] = $request->header('company');
|
||||||
$item->taxes()->create($tax);
|
$item->taxes()->create($tax);
|
||||||
}
|
}
|
||||||
@ -276,7 +291,7 @@ class EstimatesController extends Controller
|
|||||||
|
|
||||||
if ($request->has('taxes')) {
|
if ($request->has('taxes')) {
|
||||||
foreach ($request->taxes as $tax) {
|
foreach ($request->taxes as $tax) {
|
||||||
if ($tax['amount']) {
|
if (gettype($tax['amount']) !== "NULL") {
|
||||||
$tax['company_id'] = $request->header('company');
|
$tax['company_id'] = $request->header('company');
|
||||||
$estimate->taxes()->create($tax);
|
$estimate->taxes()->create($tax);
|
||||||
}
|
}
|
||||||
@ -315,10 +330,6 @@ class EstimatesController extends Controller
|
|||||||
$data['company'] = Company::find($estimate->company_id);
|
$data['company'] = Company::find($estimate->company_id);
|
||||||
|
|
||||||
$email = $data['user']['email'];
|
$email = $data['user']['email'];
|
||||||
$notificationEmail = CompanySetting::getSetting(
|
|
||||||
'notification_email',
|
|
||||||
$request->header('company')
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$email) {
|
if (!$email) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
@ -326,13 +337,7 @@ class EstimatesController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$notificationEmail) {
|
\Mail::to($email)->send(new EstimatePdf($data));
|
||||||
return response()->json([
|
|
||||||
'error' => 'notification_email_does_not_exist'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
\Mail::to($email)->send(new EstimatePdf($data, $notificationEmail));
|
|
||||||
|
|
||||||
if ($estimate->status == Estimate::STATUS_DRAFT) {
|
if ($estimate->status == Estimate::STATUS_DRAFT) {
|
||||||
$estimate->status = Estimate::STATUS_SENT;
|
$estimate->status = Estimate::STATUS_SENT;
|
||||||
@ -380,8 +385,12 @@ class EstimatesController extends Controller
|
|||||||
public function estimateToInvoice(Request $request, $id)
|
public function estimateToInvoice(Request $request, $id)
|
||||||
{
|
{
|
||||||
$estimate = Estimate::with(['items', 'items.taxes', 'user', 'estimateTemplate', 'taxes'])->find($id);
|
$estimate = Estimate::with(['items', 'items.taxes', 'user', 'estimateTemplate', 'taxes'])->find($id);
|
||||||
$invoice_date = Carbon::parse($estimate->estimate_date);
|
$invoice_date = Carbon::now();
|
||||||
$due_date = Carbon::parse($estimate->estimate_date)->addDays(7);
|
$invoice_prefix = CompanySetting::getSetting(
|
||||||
|
'invoice_prefix',
|
||||||
|
$request->header('company')
|
||||||
|
);
|
||||||
|
$due_date = Carbon::now()->addDays(7);
|
||||||
$tax_per_item = CompanySetting::getSetting(
|
$tax_per_item = CompanySetting::getSetting(
|
||||||
'tax_per_item',
|
'tax_per_item',
|
||||||
$request->header('company')
|
$request->header('company')
|
||||||
@ -400,7 +409,7 @@ class EstimatesController extends Controller
|
|||||||
$invoice = Invoice::create([
|
$invoice = Invoice::create([
|
||||||
'invoice_date' => $invoice_date,
|
'invoice_date' => $invoice_date,
|
||||||
'due_date' => $due_date,
|
'due_date' => $due_date,
|
||||||
'invoice_number' => "INV-".Invoice::getNextInvoiceNumber(),
|
'invoice_number' => $invoice_prefix."-".Invoice::getNextInvoiceNumber($invoice_prefix),
|
||||||
'reference_number' => $estimate->reference_number,
|
'reference_number' => $estimate->reference_number,
|
||||||
'user_id' => $estimate->user_id,
|
'user_id' => $estimate->user_id,
|
||||||
'company_id' => $request->header('company'),
|
'company_id' => $request->header('company'),
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Crater\Http\Controllers;
|
namespace Crater\Http\Controllers;
|
||||||
|
|
||||||
use Crater\Expense;
|
use Crater\Expense;
|
||||||
@ -17,16 +18,18 @@ class ExpensesController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$limit = $request->has('limit') ? $request->limit : 10;
|
$limit = $request->has('limit') ? $request->limit : 10;
|
||||||
|
|
||||||
$expenses = Expense::with('category')
|
$expenses = Expense::with('category')
|
||||||
|
->leftJoin('users', 'users.id', '=', 'expenses.user_id')
|
||||||
->join('expense_categories', 'expense_categories.id', '=', 'expenses.expense_category_id')
|
->join('expense_categories', 'expense_categories.id', '=', 'expenses.expense_category_id')
|
||||||
->applyFilters($request->only([
|
->applyFilters($request->only([
|
||||||
'expense_category_id',
|
'expense_category_id',
|
||||||
|
'user_id',
|
||||||
'search',
|
'search',
|
||||||
'from_date',
|
'from_date',
|
||||||
'to_date',
|
'to_date',
|
||||||
@ -34,11 +37,16 @@ class ExpensesController extends Controller
|
|||||||
'orderBy'
|
'orderBy'
|
||||||
]))
|
]))
|
||||||
->whereCompany($request->header('company'))
|
->whereCompany($request->header('company'))
|
||||||
->select('expenses.*', 'expense_categories.name')
|
->select('expenses.*', 'expense_categories.name', 'users.name as user_name')
|
||||||
->paginate($limit);
|
->paginate($limit);
|
||||||
|
|
||||||
|
$customers = User::customer()
|
||||||
|
->whereCompany($request->header('company'))
|
||||||
|
->get();
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'expenses' => $expenses,
|
'expenses' => $expenses,
|
||||||
|
'customers' => $customers,
|
||||||
'currency' => Currency::findOrFail(
|
'currency' => Currency::findOrFail(
|
||||||
CompanySetting::getSetting('currency', $request->header('company'))
|
CompanySetting::getSetting('currency', $request->header('company'))
|
||||||
)
|
)
|
||||||
@ -48,14 +56,18 @@ class ExpensesController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Show the form for creating a new resource.
|
* Show the form for creating a new resource.
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function create(Request $request)
|
public function create(Request $request)
|
||||||
{
|
{
|
||||||
$categories = ExpenseCategory::whereCompany($request->header('company'))->get();
|
$categories = ExpenseCategory::whereCompany($request->header('company'))->get();
|
||||||
|
$customers = User::customer()
|
||||||
|
->whereCompany($request->header('company'))
|
||||||
|
->get();
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'categories' => $categories
|
'categories' => $categories,
|
||||||
|
'customers' => $customers
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +75,7 @@ class ExpensesController extends Controller
|
|||||||
* Store a newly created resource in storage.
|
* Store a newly created resource in storage.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function store(ExpenseRequest $request)
|
public function store(ExpenseRequest $request)
|
||||||
{
|
{
|
||||||
@ -72,6 +84,7 @@ class ExpensesController extends Controller
|
|||||||
$expense = new Expense();
|
$expense = new Expense();
|
||||||
$expense->notes = $request->notes;
|
$expense->notes = $request->notes;
|
||||||
$expense->expense_category_id = $request->expense_category_id;
|
$expense->expense_category_id = $request->expense_category_id;
|
||||||
|
$expense->user_id = $request->user_id;
|
||||||
$expense->amount = $request->amount;
|
$expense->amount = $request->amount;
|
||||||
$expense->company_id = $request->header('company');
|
$expense->company_id = $request->header('company');
|
||||||
$expense->expense_date = $expense_date;
|
$expense->expense_date = $expense_date;
|
||||||
@ -91,7 +104,7 @@ class ExpensesController extends Controller
|
|||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*
|
*
|
||||||
* @param \Crater\Expense $expense
|
* @param \Crater\Expense $expense
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function show(Expense $expense)
|
public function show(Expense $expense)
|
||||||
{
|
{
|
||||||
@ -102,12 +115,14 @@ class ExpensesController extends Controller
|
|||||||
* Show the form for editing the specified resource.
|
* Show the form for editing the specified resource.
|
||||||
*
|
*
|
||||||
* @param $id
|
* @param $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function edit(Request $request, $id)
|
public function edit(Request $request, $id)
|
||||||
{
|
{
|
||||||
$categories = ExpenseCategory::whereCompany($request->header('company'))->get();
|
$categories = ExpenseCategory::whereCompany($request->header('company'))->get();
|
||||||
$customers = User::where('role', 'customer')->whereCompany($request->header('company'))->get();
|
$customers = User::customer()
|
||||||
|
->whereCompany($request->header('company'))
|
||||||
|
->get();
|
||||||
$expense = Expense::with('category')->where('id', $id)->first();
|
$expense = Expense::with('category')->where('id', $id)->first();
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
@ -122,7 +137,7 @@ class ExpensesController extends Controller
|
|||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param \Crater\Expense $expense
|
* @param \Crater\Expense $expense
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function update(ExpenseRequest $request, Expense $expense)
|
public function update(ExpenseRequest $request, Expense $expense)
|
||||||
{
|
{
|
||||||
@ -132,6 +147,7 @@ class ExpensesController extends Controller
|
|||||||
$expense->notes = $request->notes;
|
$expense->notes = $request->notes;
|
||||||
$expense->expense_category_id = $request->expense_category_id;
|
$expense->expense_category_id = $request->expense_category_id;
|
||||||
$expense->amount = $request->amount;
|
$expense->amount = $request->amount;
|
||||||
|
$expense->user_id = $request->user_id;
|
||||||
$expense->expense_date = $expense_date;
|
$expense->expense_date = $expense_date;
|
||||||
$expense->save();
|
$expense->save();
|
||||||
|
|
||||||
@ -150,7 +166,7 @@ class ExpensesController extends Controller
|
|||||||
* Remove the specified resource from storage.
|
* Remove the specified resource from storage.
|
||||||
*
|
*
|
||||||
* @param \Crater\Expense $expense
|
* @param \Crater\Expense $expense
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function destroy(Expense $expense)
|
public function destroy(Expense $expense)
|
||||||
{
|
{
|
||||||
@ -175,7 +191,7 @@ class ExpensesController extends Controller
|
|||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param $id
|
* @param $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function uploadReceipts(Request $request, $id)
|
public function uploadReceipts(Request $request, $id)
|
||||||
{
|
{
|
||||||
@ -200,6 +216,12 @@ class ExpensesController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrive details of an expense receipt from storage.
|
||||||
|
* @param int $id
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function showReceipt($id)
|
public function showReceipt($id)
|
||||||
{
|
{
|
||||||
$expense = Expense::find($id);
|
$expense = Expense::find($id);
|
||||||
@ -226,6 +248,14 @@ class ExpensesController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download an expense receipt from storage.
|
||||||
|
* @param int $id
|
||||||
|
* @param strig $hash
|
||||||
|
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse | \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function downloadReceipt($id, $hash)
|
public function downloadReceipt($id, $hash)
|
||||||
{
|
{
|
||||||
$company = Company::where('unique_hash', $hash)->first();
|
$company = Company::where('unique_hash', $hash)->first();
|
||||||
@ -239,13 +269,6 @@ class ExpensesController extends Controller
|
|||||||
$media = $expense->getFirstMedia('receipts');
|
$media = $expense->getFirstMedia('receipts');
|
||||||
if ($media) {
|
if ($media) {
|
||||||
$imagePath = $media->getPath();
|
$imagePath = $media->getPath();
|
||||||
$filename = $media->getPath();
|
|
||||||
$type = \File::mimeType($imagePath);
|
|
||||||
|
|
||||||
$headers = array(
|
|
||||||
'Content-Type' => $type,
|
|
||||||
);
|
|
||||||
|
|
||||||
$response = \Response::download($imagePath, $media->file_name);
|
$response = \Response::download($imagePath, $media->file_name);
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
return $response;
|
return $response;
|
||||||
@ -257,4 +280,3 @@ class ExpensesController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use Crater\Invoice;
|
|||||||
use PDF;
|
use PDF;
|
||||||
use Crater\CompanySetting;
|
use Crater\CompanySetting;
|
||||||
use Crater\Estimate;
|
use Crater\Estimate;
|
||||||
|
use Crater\Payment;
|
||||||
use Crater\User;
|
use Crater\User;
|
||||||
use Crater\Company;
|
use Crater\Company;
|
||||||
use Crater\InvoiceTemplate;
|
use Crater\InvoiceTemplate;
|
||||||
@ -118,6 +119,11 @@ class FrontendController extends Controller
|
|||||||
return $pdf->stream();
|
return $pdf->stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
public function getCustomerInvoicePdf($id)
|
public function getCustomerInvoicePdf($id)
|
||||||
{
|
{
|
||||||
$invoice = Invoice::with([
|
$invoice = Invoice::with([
|
||||||
@ -371,4 +377,34 @@ class FrontendController extends Controller
|
|||||||
|
|
||||||
return $pdf->stream();
|
return $pdf->stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPaymentPdf($id)
|
||||||
|
{
|
||||||
|
$payment = Payment::with([
|
||||||
|
'user',
|
||||||
|
'invoice',
|
||||||
|
'paymentMethod'
|
||||||
|
])
|
||||||
|
->where('unique_hash', $id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
$company = Company::find($payment->company_id);
|
||||||
|
$companyAddress = User::with(['addresses', 'addresses.country'])->find(1);
|
||||||
|
|
||||||
|
$logo = $company->getMedia('logo')->first();
|
||||||
|
|
||||||
|
if($logo) {
|
||||||
|
$logo = $logo->getFullUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
view()->share([
|
||||||
|
'payment' => $payment,
|
||||||
|
'company_address' => $companyAddress,
|
||||||
|
'logo' => $logo ?? null
|
||||||
|
]);
|
||||||
|
|
||||||
|
$pdf = PDF::loadView('app.pdf.payment.payment');
|
||||||
|
|
||||||
|
return $pdf->stream();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ use Crater\Invoice;
|
|||||||
use Crater\InvoiceItem;
|
use Crater\InvoiceItem;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Crater\Item;
|
use Crater\Item;
|
||||||
use Crater\Mail\invoicePdf;
|
use Crater\Mail\InvoicePdf;
|
||||||
use function MongoDB\BSON\toJSON;
|
use function MongoDB\BSON\toJSON;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Crater\User;
|
use Crater\User;
|
||||||
@ -27,7 +27,7 @@ class InvoicesController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
@ -60,20 +60,30 @@ class InvoicesController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Show the form for creating a new resource.
|
* Show the form for creating a new resource.
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function create(Request $request)
|
public function create(Request $request)
|
||||||
{
|
{
|
||||||
$tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company'));
|
$tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company'));
|
||||||
$discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company'));
|
$discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company'));
|
||||||
$nextInvoiceNumber = "INV-".Invoice::getNextInvoiceNumber();
|
$invoice_prefix = CompanySetting::getSetting('invoice_prefix', $request->header('company'));
|
||||||
|
$invoice_num_auto_generate = CompanySetting::getSetting('invoice_auto_generate', $request->header('company'));
|
||||||
|
|
||||||
|
$nextInvoiceNumberAttribute = null;
|
||||||
|
$nextInvoiceNumber = Invoice::getNextInvoiceNumber($invoice_prefix);
|
||||||
|
|
||||||
|
if ($invoice_num_auto_generate == "YES") {
|
||||||
|
$nextInvoiceNumberAttribute = $nextInvoiceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'nextInvoiceNumber' => $nextInvoiceNumber,
|
'nextInvoiceNumberAttribute' => $nextInvoiceNumberAttribute,
|
||||||
|
'nextInvoiceNumber' => $invoice_prefix.'-'.$nextInvoiceNumber,
|
||||||
'items' => Item::with('taxes')->whereCompany($request->header('company'))->get(),
|
'items' => Item::with('taxes')->whereCompany($request->header('company'))->get(),
|
||||||
'invoiceTemplates' => InvoiceTemplate::all(),
|
'invoiceTemplates' => InvoiceTemplate::all(),
|
||||||
'tax_per_item' => $tax_per_item,
|
'tax_per_item' => $tax_per_item,
|
||||||
'discount_per_item' => $discount_per_item
|
'discount_per_item' => $discount_per_item,
|
||||||
|
'invoice_prefix' => $invoice_prefix
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,10 +91,17 @@ class InvoicesController extends Controller
|
|||||||
* Store a newly created resource in storage.
|
* Store a newly created resource in storage.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function store(Requests\InvoicesRequest $request)
|
public function store(Requests\InvoicesRequest $request)
|
||||||
{
|
{
|
||||||
|
$invoice_number = explode("-",$request->invoice_number);
|
||||||
|
$number_attributes['invoice_number'] = $invoice_number[0].'-'.sprintf('%06d', intval($invoice_number[1]));
|
||||||
|
|
||||||
|
Validator::make($number_attributes, [
|
||||||
|
'invoice_number' => 'required|unique:invoices,invoice_number'
|
||||||
|
])->validate();
|
||||||
|
|
||||||
$invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date);
|
$invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date);
|
||||||
$due_date = Carbon::createFromFormat('d/m/Y', $request->due_date);
|
$due_date = Carbon::createFromFormat('d/m/Y', $request->due_date);
|
||||||
$status = Invoice::STATUS_DRAFT;
|
$status = Invoice::STATUS_DRAFT;
|
||||||
@ -99,7 +116,7 @@ class InvoicesController extends Controller
|
|||||||
$invoice = Invoice::create([
|
$invoice = Invoice::create([
|
||||||
'invoice_date' => $invoice_date,
|
'invoice_date' => $invoice_date,
|
||||||
'due_date' => $due_date,
|
'due_date' => $due_date,
|
||||||
'invoice_number' => $request->invoice_number,
|
'invoice_number' => $number_attributes['invoice_number'],
|
||||||
'reference_number' => $request->reference_number,
|
'reference_number' => $request->reference_number,
|
||||||
'user_id' => $request->user_id,
|
'user_id' => $request->user_id,
|
||||||
'company_id' => $request->header('company'),
|
'company_id' => $request->header('company'),
|
||||||
@ -128,8 +145,7 @@ class InvoicesController extends Controller
|
|||||||
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
|
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
|
||||||
foreach ($invoiceItem['taxes'] as $tax) {
|
foreach ($invoiceItem['taxes'] as $tax) {
|
||||||
$tax['company_id'] = $request->header('company');
|
$tax['company_id'] = $request->header('company');
|
||||||
|
if (gettype($tax['amount']) !== "NULL") {
|
||||||
if ($tax['amount']) {
|
|
||||||
$item->taxes()->create($tax);
|
$item->taxes()->create($tax);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,7 +156,7 @@ class InvoicesController extends Controller
|
|||||||
foreach ($request->taxes as $tax) {
|
foreach ($request->taxes as $tax) {
|
||||||
$tax['company_id'] = $request->header('company');
|
$tax['company_id'] = $request->header('company');
|
||||||
|
|
||||||
if ($tax['amount']) {
|
if (gettype($tax['amount']) !== "NULL") {
|
||||||
$invoice->taxes()->create($tax);
|
$invoice->taxes()->create($tax);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,11 +167,6 @@ class InvoicesController extends Controller
|
|||||||
$data['user'] = User::find($request->user_id)->toArray();
|
$data['user'] = User::find($request->user_id)->toArray();
|
||||||
$data['company'] = Company::find($invoice->company_id);
|
$data['company'] = Company::find($invoice->company_id);
|
||||||
|
|
||||||
$notificationEmail = CompanySetting::getSetting(
|
|
||||||
'notification_email',
|
|
||||||
$request->header('company')
|
|
||||||
);
|
|
||||||
|
|
||||||
$email = $data['user']['email'];
|
$email = $data['user']['email'];
|
||||||
|
|
||||||
if (!$email) {
|
if (!$email) {
|
||||||
@ -164,13 +175,7 @@ class InvoicesController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$notificationEmail) {
|
\Mail::to($email)->send(new InvoicePdf($data));
|
||||||
return response()->json([
|
|
||||||
'error' => 'notification_email_does_not_exist'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
\Mail::to($email)->send(new invoicePdf($data, $notificationEmail));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoice = Invoice::with(['items', 'user', 'invoiceTemplate', 'taxes'])->find($invoice->id);
|
$invoice = Invoice::with(['items', 'user', 'invoiceTemplate', 'taxes'])->find($invoice->id);
|
||||||
@ -185,7 +190,7 @@ class InvoicesController extends Controller
|
|||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function show(Request $request, $id)
|
public function show(Request $request, $id)
|
||||||
{
|
{
|
||||||
@ -209,7 +214,7 @@ class InvoicesController extends Controller
|
|||||||
* Show the form for editing the specified resource.
|
* Show the form for editing the specified resource.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function edit(Request $request,$id)
|
public function edit(Request $request,$id)
|
||||||
{
|
{
|
||||||
@ -222,12 +227,13 @@ class InvoicesController extends Controller
|
|||||||
])->find($id);
|
])->find($id);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'nextInvoiceNumber' => $invoice->invoice_number,
|
'nextInvoiceNumber' => $invoice->getInvoiceNumAttribute(),
|
||||||
'invoice' => $invoice,
|
'invoice' => $invoice,
|
||||||
'invoiceTemplates' => InvoiceTemplate::all(),
|
'invoiceTemplates' => InvoiceTemplate::all(),
|
||||||
'tax_per_item' => $invoice->tax_per_item,
|
'tax_per_item' => $invoice->tax_per_item,
|
||||||
'discount_per_item' => $invoice->discount_per_item,
|
'discount_per_item' => $invoice->discount_per_item,
|
||||||
'shareable_link' => url('/invoices/pdf/'.$invoice->unique_hash)
|
'shareable_link' => url('/invoices/pdf/'.$invoice->unique_hash),
|
||||||
|
'invoice_prefix' => $invoice->getInvoicePrefixAttribute()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,10 +242,17 @@ class InvoicesController extends Controller
|
|||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function update(Requests\InvoicesRequest $request, $id)
|
public function update(Requests\InvoicesRequest $request, $id)
|
||||||
{
|
{
|
||||||
|
$invoice_number = explode("-",$request->invoice_number);
|
||||||
|
$number_attributes['invoice_number'] = $invoice_number[0].'-'.sprintf('%06d', intval($invoice_number[1]));
|
||||||
|
|
||||||
|
Validator::make($number_attributes, [
|
||||||
|
'invoice_number' => 'required|unique:invoices,invoice_number'.','.$id
|
||||||
|
])->validate();
|
||||||
|
|
||||||
$invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date);
|
$invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date);
|
||||||
$due_date = Carbon::createFromFormat('d/m/Y', $request->due_date);
|
$due_date = Carbon::createFromFormat('d/m/Y', $request->due_date);
|
||||||
|
|
||||||
@ -268,7 +281,7 @@ class InvoicesController extends Controller
|
|||||||
|
|
||||||
$invoice->invoice_date = $invoice_date;
|
$invoice->invoice_date = $invoice_date;
|
||||||
$invoice->due_date = $due_date;
|
$invoice->due_date = $due_date;
|
||||||
$invoice->invoice_number = $request->invoice_number;
|
$invoice->invoice_number = $number_attributes['invoice_number'];
|
||||||
$invoice->reference_number = $request->reference_number;
|
$invoice->reference_number = $request->reference_number;
|
||||||
$invoice->user_id = $request->user_id;
|
$invoice->user_id = $request->user_id;
|
||||||
$invoice->invoice_template_id = $request->invoice_template_id;
|
$invoice->invoice_template_id = $request->invoice_template_id;
|
||||||
@ -292,7 +305,6 @@ class InvoicesController extends Controller
|
|||||||
foreach ($oldTaxes as $oldTax) {
|
foreach ($oldTaxes as $oldTax) {
|
||||||
Tax::destroy($oldTax['id']);
|
Tax::destroy($oldTax['id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($invoiceItems as $invoiceItem) {
|
foreach ($invoiceItems as $invoiceItem) {
|
||||||
$invoiceItem['company_id'] = $request->header('company');
|
$invoiceItem['company_id'] = $request->header('company');
|
||||||
$item = $invoice->items()->create($invoiceItem);
|
$item = $invoice->items()->create($invoiceItem);
|
||||||
@ -300,8 +312,7 @@ class InvoicesController extends Controller
|
|||||||
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
|
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
|
||||||
foreach ($invoiceItem['taxes'] as $tax) {
|
foreach ($invoiceItem['taxes'] as $tax) {
|
||||||
$tax['company_id'] = $request->header('company');
|
$tax['company_id'] = $request->header('company');
|
||||||
|
if (gettype($tax['amount']) !== "NULL") {
|
||||||
if ($tax['amount']) {
|
|
||||||
$item->taxes()->create($tax);
|
$item->taxes()->create($tax);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -312,7 +323,7 @@ class InvoicesController extends Controller
|
|||||||
foreach ($request->taxes as $tax) {
|
foreach ($request->taxes as $tax) {
|
||||||
$tax['company_id'] = $request->header('company');
|
$tax['company_id'] = $request->header('company');
|
||||||
|
|
||||||
if ($tax['amount']) {
|
if (gettype($tax['amount']) !== "NULL") {
|
||||||
$invoice->taxes()->create($tax);
|
$invoice->taxes()->create($tax);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,7 +342,7 @@ class InvoicesController extends Controller
|
|||||||
* Remove the specified resource from storage.
|
* Remove the specified resource from storage.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id)
|
||||||
{
|
{
|
||||||
@ -369,6 +380,14 @@ class InvoicesController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mail a specific invoice to the correponding cusitomer's email address.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function sendInvoice(Request $request)
|
public function sendInvoice(Request $request)
|
||||||
{
|
{
|
||||||
$invoice = Invoice::findOrFail($request->id);
|
$invoice = Invoice::findOrFail($request->id);
|
||||||
@ -378,10 +397,6 @@ class InvoicesController extends Controller
|
|||||||
$data['user'] = User::find($userId)->toArray();
|
$data['user'] = User::find($userId)->toArray();
|
||||||
$data['company'] = Company::find($invoice->company_id);
|
$data['company'] = Company::find($invoice->company_id);
|
||||||
$email = $data['user']['email'];
|
$email = $data['user']['email'];
|
||||||
$notificationEmail = CompanySetting::getSetting(
|
|
||||||
'notification_email',
|
|
||||||
$request->header('company')
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$email) {
|
if (!$email) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
@ -389,13 +404,7 @@ class InvoicesController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$notificationEmail) {
|
\Mail::to($email)->send(new InvoicePdf($data));
|
||||||
return response()->json([
|
|
||||||
'error' => 'notification_email_does_not_exist'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
\Mail::to($email)->send(new invoicePdf($data, $notificationEmail));
|
|
||||||
|
|
||||||
if ($invoice->status == Invoice::STATUS_DRAFT) {
|
if ($invoice->status == Invoice::STATUS_DRAFT) {
|
||||||
$invoice->status = Invoice::STATUS_SENT;
|
$invoice->status = Invoice::STATUS_SENT;
|
||||||
@ -409,6 +418,13 @@ class InvoicesController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a specific invoice as sent.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function markAsSent(Request $request)
|
public function markAsSent(Request $request)
|
||||||
{
|
{
|
||||||
$invoice = Invoice::findOrFail($request->id);
|
$invoice = Invoice::findOrFail($request->id);
|
||||||
@ -421,6 +437,13 @@ class InvoicesController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a specific invoice as paid.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function markAsPaid(Request $request)
|
public function markAsPaid(Request $request)
|
||||||
{
|
{
|
||||||
$invoice = Invoice::findOrFail($request->id);
|
$invoice = Invoice::findOrFail($request->id);
|
||||||
@ -434,6 +457,14 @@ class InvoicesController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrive a specified user's unpaid invoices from storage.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param int $id
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function getCustomersUnpaidInvoices(Request $request, $id)
|
public function getCustomersUnpaidInvoices(Request $request, $id)
|
||||||
{
|
{
|
||||||
$invoices = Invoice::where('paid_status', '<>', Invoice::STATUS_PAID)
|
$invoices = Invoice::where('paid_status', '<>', Invoice::STATUS_PAID)
|
||||||
@ -445,4 +476,94 @@ class InvoicesController extends Controller
|
|||||||
'invoices' => $invoices
|
'invoices' => $invoices
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function cloneInvoice(Request $request)
|
||||||
|
{
|
||||||
|
$oldInvoice = Invoice::with([
|
||||||
|
'items.taxes',
|
||||||
|
'user',
|
||||||
|
'invoiceTemplate',
|
||||||
|
'taxes.taxType'
|
||||||
|
])
|
||||||
|
->find($request->id);
|
||||||
|
|
||||||
|
$date = Carbon::now();
|
||||||
|
$invoice_prefix = CompanySetting::getSetting(
|
||||||
|
'invoice_prefix',
|
||||||
|
$request->header('company')
|
||||||
|
);
|
||||||
|
$tax_per_item = CompanySetting::getSetting(
|
||||||
|
'tax_per_item',
|
||||||
|
$request->header('company')
|
||||||
|
) ? CompanySetting::getSetting(
|
||||||
|
'tax_per_item',
|
||||||
|
$request->header('company')
|
||||||
|
) : 'NO';
|
||||||
|
$discount_per_item = CompanySetting::getSetting(
|
||||||
|
'discount_per_item',
|
||||||
|
$request->header('company')
|
||||||
|
) ? CompanySetting::getSetting(
|
||||||
|
'discount_per_item',
|
||||||
|
$request->header('company')
|
||||||
|
) : 'NO';
|
||||||
|
|
||||||
|
$invoice = Invoice::create([
|
||||||
|
'invoice_date' => $date,
|
||||||
|
'due_date' => $date,
|
||||||
|
'invoice_number' => $invoice_prefix."-".Invoice::getNextInvoiceNumber($invoice_prefix),
|
||||||
|
'reference_number' => $oldInvoice->reference_number,
|
||||||
|
'user_id' => $oldInvoice->user_id,
|
||||||
|
'company_id' => $request->header('company'),
|
||||||
|
'invoice_template_id' => 1,
|
||||||
|
'status' => Invoice::STATUS_DRAFT,
|
||||||
|
'paid_status' => Invoice::STATUS_UNPAID,
|
||||||
|
'sub_total' => $oldInvoice->sub_total,
|
||||||
|
'discount' => $oldInvoice->discount,
|
||||||
|
'discount_type' => $oldInvoice->discount_type,
|
||||||
|
'discount_val' => $oldInvoice->discount_val,
|
||||||
|
'total' => $oldInvoice->total,
|
||||||
|
'due_amount' => $oldInvoice->total,
|
||||||
|
'tax_per_item' => $oldInvoice->tax_per_item,
|
||||||
|
'discount_per_item' => $oldInvoice->discount_per_item,
|
||||||
|
'tax' => $oldInvoice->tax,
|
||||||
|
'notes' => $oldInvoice->notes,
|
||||||
|
'unique_hash' => str_random(60)
|
||||||
|
]);
|
||||||
|
|
||||||
|
$invoiceItems = $oldInvoice->items->toArray();
|
||||||
|
|
||||||
|
foreach ($invoiceItems as $invoiceItem) {
|
||||||
|
$invoiceItem['company_id'] = $request->header('company');
|
||||||
|
$invoiceItem['name'] = $invoiceItem['name'];
|
||||||
|
$item = $invoice->items()->create($invoiceItem);
|
||||||
|
|
||||||
|
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
|
||||||
|
foreach ($invoiceItem['taxes'] as $tax) {
|
||||||
|
$tax['company_id'] = $request->header('company');
|
||||||
|
|
||||||
|
if ($tax['amount']) {
|
||||||
|
$item->taxes()->create($tax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($oldInvoice->taxes) {
|
||||||
|
foreach ($oldInvoice->taxes->toArray() as $tax) {
|
||||||
|
$tax['company_id'] = $request->header('company');
|
||||||
|
$invoice->taxes()->create($tax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice = Invoice::with([
|
||||||
|
'items',
|
||||||
|
'user',
|
||||||
|
'invoiceTemplate',
|
||||||
|
'taxes'
|
||||||
|
])->find($invoice->id);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'invoice' => $invoice
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,14 +14,17 @@ class ItemsController extends Controller
|
|||||||
{
|
{
|
||||||
$limit = $request->has('limit') ? $request->limit : 10;
|
$limit = $request->has('limit') ? $request->limit : 10;
|
||||||
|
|
||||||
$items = Item::applyFilters($request->only([
|
$items = Item::with(['taxes'])
|
||||||
|
->leftJoin('units', 'units.id', '=', 'items.unit_id')
|
||||||
|
->applyFilters($request->only([
|
||||||
'search',
|
'search',
|
||||||
'price',
|
'price',
|
||||||
'unit',
|
'unit_id',
|
||||||
'orderByField',
|
'orderByField',
|
||||||
'orderBy'
|
'orderBy'
|
||||||
]))
|
]))
|
||||||
->whereCompany($request->header('company'))
|
->whereCompany($request->header('company'))
|
||||||
|
->select('items.*', 'units.name as unit_name')
|
||||||
->latest()
|
->latest()
|
||||||
->paginate($limit);
|
->paginate($limit);
|
||||||
|
|
||||||
@ -33,7 +36,7 @@ class ItemsController extends Controller
|
|||||||
|
|
||||||
public function edit(Request $request, $id)
|
public function edit(Request $request, $id)
|
||||||
{
|
{
|
||||||
$item = Item::with('taxes')->find($id);
|
$item = Item::with(['taxes', 'unit'])->find($id);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'item' => $item,
|
'item' => $item,
|
||||||
@ -43,11 +46,18 @@ class ItemsController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Item.
|
||||||
|
*
|
||||||
|
* @param Crater\Http\Requests\ItemsRequest $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function store(Requests\ItemsRequest $request)
|
public function store(Requests\ItemsRequest $request)
|
||||||
{
|
{
|
||||||
$item = new Item();
|
$item = new Item();
|
||||||
$item->name = $request->name;
|
$item->name = $request->name;
|
||||||
$item->unit = $request->unit;
|
$item->unit_id = $request->unit_id;
|
||||||
$item->description = $request->description;
|
$item->description = $request->description;
|
||||||
$item->company_id = $request->header('company');
|
$item->company_id = $request->header('company');
|
||||||
$item->price = $request->price;
|
$item->price = $request->price;
|
||||||
@ -67,11 +77,18 @@ class ItemsController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an existing Item.
|
||||||
|
*
|
||||||
|
* @param Crater\Http\Requests\ItemsRequest $request
|
||||||
|
* @param int $id
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function update(Requests\ItemsRequest $request, $id)
|
public function update(Requests\ItemsRequest $request, $id)
|
||||||
{
|
{
|
||||||
$item = Item::find($id);
|
$item = Item::find($id);
|
||||||
$item->name = $request->name;
|
$item->name = $request->name;
|
||||||
$item->unit = $request->unit;
|
$item->unit_id = $request->unit_id;
|
||||||
$item->description = $request->description;
|
$item->description = $request->description;
|
||||||
$item->price = $request->price;
|
$item->price = $request->price;
|
||||||
$item->save();
|
$item->save();
|
||||||
@ -96,6 +113,13 @@ class ItemsController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an existing Item.
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id)
|
||||||
{
|
{
|
||||||
$data = Item::deleteItem($id);
|
$data = Item::deleteItem($id);
|
||||||
@ -111,12 +135,20 @@ class ItemsController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a list of existing Items.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function delete(Request $request)
|
public function delete(Request $request)
|
||||||
{
|
{
|
||||||
$items = [];
|
$items = [];
|
||||||
foreach ($request->id as $id) {
|
foreach ($request->id as $id) {
|
||||||
$item = Item::deleteItem($id);
|
$item = Item::deleteItem($id);
|
||||||
if (!$item) {
|
if ($item) {
|
||||||
array_push($items, $id);
|
array_push($items, $id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,12 @@ use Crater\Country;
|
|||||||
|
|
||||||
class LocationController extends Controller
|
class LocationController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrive a list of Countries.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function getCountries()
|
public function getCountries()
|
||||||
{
|
{
|
||||||
return response()->json([
|
return response()->json([
|
||||||
|
|||||||
@ -18,6 +18,13 @@ use Illuminate\Support\Facades\Artisan;
|
|||||||
|
|
||||||
class OnboardingController extends Controller
|
class OnboardingController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve Onboarding data.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function getOnboardingData(Request $request)
|
public function getOnboardingData(Request $request)
|
||||||
{
|
{
|
||||||
if (!\Storage::disk('local')->has('database_created')) {
|
if (!\Storage::disk('local')->has('database_created')) {
|
||||||
@ -37,9 +44,14 @@ class OnboardingController extends Controller
|
|||||||
$date_formats = DateFormatter::get_list();
|
$date_formats = DateFormatter::get_list();
|
||||||
$time_zones = TimeZones::get_list();
|
$time_zones = TimeZones::get_list();
|
||||||
$languages = [
|
$languages = [
|
||||||
|
["code"=>"ar", "name" => "Arabic"],
|
||||||
["code"=>"en", "name" => "English"],
|
["code"=>"en", "name" => "English"],
|
||||||
["code"=>"fr", "name" => "French"],
|
["code"=>"fr", "name" => "French"],
|
||||||
["code"=>"es", "name" => "Spanish"]
|
["code"=>"es", "name" => "Spanish"],
|
||||||
|
["code"=>"ar", "name" => "العربية"],
|
||||||
|
["code"=>"de", "name" => "German"],
|
||||||
|
["code"=>"pt-br", "name" => "Portuguese (Brazilian)"],
|
||||||
|
["code"=>"it", "name" => "Italian"],
|
||||||
];
|
];
|
||||||
$fiscal_years = [
|
$fiscal_years = [
|
||||||
['key' => 'january-december' , 'value' => '1-12'],
|
['key' => 'january-december' , 'value' => '1-12'],
|
||||||
@ -72,6 +84,13 @@ class OnboardingController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup Admin Profile.
|
||||||
|
*
|
||||||
|
* @param \Crater\Http\Requests\ProfileRequest $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function adminProfile(ProfileRequest $request)
|
public function adminProfile(ProfileRequest $request)
|
||||||
{
|
{
|
||||||
$setting = Setting::getSetting('profile_complete');
|
$setting = Setting::getSetting('profile_complete');
|
||||||
@ -97,6 +116,12 @@ class OnboardingController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup Admin Avatar.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function uploadAdminAvatar(Request $request)
|
public function uploadAdminAvatar(Request $request)
|
||||||
{
|
{
|
||||||
$setting = Setting::getSetting('profile_complete');
|
$setting = Setting::getSetting('profile_complete');
|
||||||
@ -123,6 +148,12 @@ class OnboardingController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup Admin Company.
|
||||||
|
*
|
||||||
|
* @param \Crater\Http\Requests\CompanyRequest $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function adminCompany(CompanyRequest $request)
|
public function adminCompany(CompanyRequest $request)
|
||||||
{
|
{
|
||||||
$setting = Setting::getSetting('profile_complete');
|
$setting = Setting::getSetting('profile_complete');
|
||||||
@ -174,6 +205,13 @@ class OnboardingController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup Company Settings.
|
||||||
|
*
|
||||||
|
* @param \Crater\Http\Requests\CompanySettingRequest $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function companySettings(CompanySettingRequest $request)
|
public function companySettings(CompanySettingRequest $request)
|
||||||
{
|
{
|
||||||
$setting = Setting::getSetting('profile_complete');
|
$setting = Setting::getSetting('profile_complete');
|
||||||
@ -202,6 +240,45 @@ class OnboardingController extends Controller
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$invoices = [
|
||||||
|
'invoice_auto_generate' => 'YES',
|
||||||
|
'invoice_prefix' => 'INV'
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($invoices as $key => $value) {
|
||||||
|
CompanySetting::setSetting(
|
||||||
|
$key,
|
||||||
|
$value,
|
||||||
|
$user->company_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$estimates = [
|
||||||
|
'estimate_prefix' => 'EST',
|
||||||
|
'estimate_auto_generate' => 'YES'
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($estimates as $key => $value) {
|
||||||
|
CompanySetting::setSetting(
|
||||||
|
$key,
|
||||||
|
$value,
|
||||||
|
$user->company_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$payments = [
|
||||||
|
'payment_prefix' => 'PAY',
|
||||||
|
'payment_auto_generate' => 'YES'
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($payments as $key => $value) {
|
||||||
|
CompanySetting::setSetting(
|
||||||
|
$key,
|
||||||
|
$value,
|
||||||
|
$user->company_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$colors = [
|
$colors = [
|
||||||
'primary_text_color' => '#5851D8',
|
'primary_text_color' => '#5851D8',
|
||||||
'heading_text_color' => '#595959',
|
'heading_text_color' => '#595959',
|
||||||
@ -232,13 +309,24 @@ class OnboardingController extends Controller
|
|||||||
|
|
||||||
Artisan::call('passport:install --force');
|
Artisan::call('passport:install --force');
|
||||||
|
|
||||||
|
Artisan::call('db:seed', ['--class' => 'PaymentMethodSeeder', '--force' => true]);
|
||||||
|
|
||||||
|
Artisan::call('db:seed', ['--class' => 'UnitSeeder', '--force' => true]);
|
||||||
|
|
||||||
$client = DB::table('oauth_clients')->find(2);
|
$client = DB::table('oauth_clients')->find(2);
|
||||||
|
|
||||||
$path = base_path('.env');
|
$path = base_path('.env');
|
||||||
|
|
||||||
if (file_exists($path)) {
|
if (file_exists($path)) {
|
||||||
file_put_contents($path, str_replace(
|
file_put_contents($path, str_replace(
|
||||||
'PROXY_OAUTH_CLIENT_SECRET='.config('auth.proxy.client_secret'), 'PROXY_OAUTH_CLIENT_SECRET='.$client->secret, file_get_contents($path)
|
'PROXY_OAUTH_CLIENT_SECRET='.config('auth.proxy.client_secret'),
|
||||||
|
'PROXY_OAUTH_CLIENT_SECRET='.$client->secret,
|
||||||
|
file_get_contents($path)
|
||||||
|
));
|
||||||
|
file_put_contents($path, str_replace(
|
||||||
|
'APP_DEBUG=true',
|
||||||
|
'APP_DEBUG=false',
|
||||||
|
file_get_contents($path)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,12 +4,16 @@ namespace Crater\Http\Controllers;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Crater\CompanySetting;
|
use Crater\CompanySetting;
|
||||||
use Crater\Currency;
|
use Crater\Currency;
|
||||||
|
use Crater\Company;
|
||||||
use Crater\Invoice;
|
use Crater\Invoice;
|
||||||
use Crater\Payment;
|
use Crater\Payment;
|
||||||
|
use Crater\PaymentMethod;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use function MongoDB\BSON\toJSON;
|
use function MongoDB\BSON\toJSON;
|
||||||
use Crater\User;
|
use Crater\User;
|
||||||
use Crater\Http\Requests\PaymentRequest;
|
use Crater\Http\Requests\PaymentRequest;
|
||||||
|
use Validator;
|
||||||
|
use Crater\Mail\PaymentPdf;
|
||||||
|
|
||||||
class PaymentController extends Controller
|
class PaymentController extends Controller
|
||||||
{
|
{
|
||||||
@ -22,19 +26,20 @@ class PaymentController extends Controller
|
|||||||
{
|
{
|
||||||
$limit = $request->has('limit') ? $request->limit : 10;
|
$limit = $request->has('limit') ? $request->limit : 10;
|
||||||
|
|
||||||
$payments = Payment::with('user', 'invoice')
|
$payments = Payment::with(['user', 'invoice', 'paymentMethod'])
|
||||||
->join('users', 'users.id', '=', 'payments.user_id')
|
->join('users', 'users.id', '=', 'payments.user_id')
|
||||||
->leftJoin('invoices', 'invoices.id', '=', 'payments.invoice_id')
|
->leftJoin('invoices', 'invoices.id', '=', 'payments.invoice_id')
|
||||||
|
->leftJoin('payment_methods', 'payment_methods.id', '=', 'payments.payment_method_id')
|
||||||
->applyFilters($request->only([
|
->applyFilters($request->only([
|
||||||
'search',
|
'search',
|
||||||
'payment_number',
|
'payment_number',
|
||||||
'payment_mode',
|
'payment_method_id',
|
||||||
'customer_id',
|
'customer_id',
|
||||||
'orderByField',
|
'orderByField',
|
||||||
'orderBy'
|
'orderBy'
|
||||||
]))
|
]))
|
||||||
->whereCompany($request->header('company'))
|
->whereCompany($request->header('company'))
|
||||||
->select('payments.*', 'users.name', 'invoices.invoice_number')
|
->select('payments.*', 'users.name', 'invoices.invoice_number', 'payment_methods.name as payment_mode')
|
||||||
->latest()
|
->latest()
|
||||||
->paginate($limit);
|
->paginate($limit);
|
||||||
|
|
||||||
@ -50,13 +55,27 @@ class PaymentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create(Request $request)
|
public function create(Request $request)
|
||||||
{
|
{
|
||||||
$nextPaymentNumber = 'PAY-'.Payment::getNextPaymentNumber();
|
$payment_prefix = CompanySetting::getSetting('payment_prefix', $request->header('company'));
|
||||||
|
$payment_num_auto_generate = CompanySetting::getSetting('payment_auto_generate', $request->header('company'));
|
||||||
|
|
||||||
|
|
||||||
|
$nextPaymentNumberAttribute = null;
|
||||||
|
$nextPaymentNumber = Payment::getNextPaymentNumber($payment_prefix);
|
||||||
|
|
||||||
|
if ($payment_num_auto_generate == "YES") {
|
||||||
|
$nextPaymentNumberAttribute = $nextPaymentNumber;
|
||||||
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'customers' => User::where('role', 'customer')
|
'customers' => User::where('role', 'customer')
|
||||||
->whereCompany($request->header('company'))
|
->whereCompany($request->header('company'))
|
||||||
->get(),
|
->get(),
|
||||||
'nextPaymentNumber' => $nextPaymentNumber
|
'paymentMethods' => PaymentMethod::whereCompany($request->header('company'))
|
||||||
|
->latest()
|
||||||
|
->get(),
|
||||||
|
'nextPaymentNumberAttribute' => $nextPaymentNumberAttribute,
|
||||||
|
'nextPaymentNumber' => $payment_prefix.'-'.$nextPaymentNumber,
|
||||||
|
'payment_prefix' => $payment_prefix
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +87,13 @@ class PaymentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(PaymentRequest $request)
|
public function store(PaymentRequest $request)
|
||||||
{
|
{
|
||||||
|
$payment_number = explode("-",$request->payment_number);
|
||||||
|
$number_attributes['payment_number'] = $payment_number[0].'-'.sprintf('%06d', intval($payment_number[1]));
|
||||||
|
|
||||||
|
Validator::make($number_attributes, [
|
||||||
|
'payment_number' => 'required|unique:payments,payment_number'
|
||||||
|
])->validate();
|
||||||
|
|
||||||
$payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date);
|
$payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date);
|
||||||
|
|
||||||
if ($request->has('invoice_id') && $request->invoice_id != null) {
|
if ($request->has('invoice_id') && $request->invoice_id != null) {
|
||||||
@ -90,17 +116,19 @@ class PaymentController extends Controller
|
|||||||
|
|
||||||
$payment = Payment::create([
|
$payment = Payment::create([
|
||||||
'payment_date' => $payment_date,
|
'payment_date' => $payment_date,
|
||||||
'payment_number' => $request->payment_number,
|
'payment_number' => $number_attributes['payment_number'],
|
||||||
'user_id' => $request->user_id,
|
'user_id' => $request->user_id,
|
||||||
'company_id' => $request->header('company'),
|
'company_id' => $request->header('company'),
|
||||||
'invoice_id' => $request->invoice_id,
|
'invoice_id' => $request->invoice_id,
|
||||||
'payment_mode' => $request->payment_mode,
|
'payment_method_id' => $request->payment_method_id,
|
||||||
'amount' => $request->amount,
|
'amount' => $request->amount,
|
||||||
'notes' => $request->notes,
|
'notes' => $request->notes,
|
||||||
|
'unique_hash' => str_random(60)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'payment' => $payment,
|
'payment' => $payment,
|
||||||
|
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash),
|
||||||
'success' => true
|
'success' => true
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -113,7 +141,12 @@ class PaymentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function show($id)
|
public function show($id)
|
||||||
{
|
{
|
||||||
//
|
$payment = Payment::with(['user', 'invoice', 'paymentMethod'])->find($id);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'payment' => $payment,
|
||||||
|
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash)
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -124,7 +157,7 @@ class PaymentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function edit(Request $request, $id)
|
public function edit(Request $request, $id)
|
||||||
{
|
{
|
||||||
$payment = Payment::with('user', 'invoice')->find($id);
|
$payment = Payment::with(['user', 'invoice', 'paymentMethod'])->find($id);
|
||||||
|
|
||||||
$invoices = Invoice::where('paid_status', '<>', Invoice::STATUS_PAID)
|
$invoices = Invoice::where('paid_status', '<>', Invoice::STATUS_PAID)
|
||||||
->where('user_id', $payment->user_id)->where('due_amount', '>', 0)
|
->where('user_id', $payment->user_id)->where('due_amount', '>', 0)
|
||||||
@ -135,7 +168,12 @@ class PaymentController extends Controller
|
|||||||
'customers' => User::where('role', 'customer')
|
'customers' => User::where('role', 'customer')
|
||||||
->whereCompany($request->header('company'))
|
->whereCompany($request->header('company'))
|
||||||
->get(),
|
->get(),
|
||||||
'nextPaymentNumber' => $payment->payment_number,
|
'paymentMethods' => PaymentMethod::whereCompany($request->header('company'))
|
||||||
|
->latest()
|
||||||
|
->get(),
|
||||||
|
'nextPaymentNumber' => $payment->getPaymentNumAttribute(),
|
||||||
|
'payment_prefix' => $payment->getPaymentPrefixAttribute(),
|
||||||
|
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash),
|
||||||
'payment' => $payment,
|
'payment' => $payment,
|
||||||
'invoices' => $invoices
|
'invoices' => $invoices
|
||||||
]);
|
]);
|
||||||
@ -150,6 +188,13 @@ class PaymentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function update(PaymentRequest $request, $id)
|
public function update(PaymentRequest $request, $id)
|
||||||
{
|
{
|
||||||
|
$payment_number = explode("-",$request->payment_number);
|
||||||
|
$number_attributes['payment_number'] = $payment_number[0].'-'.sprintf('%06d', intval($payment_number[1]));
|
||||||
|
|
||||||
|
Validator::make($number_attributes, [
|
||||||
|
'payment_number' => 'required|unique:payments,payment_number'.','.$id
|
||||||
|
])->validate();
|
||||||
|
|
||||||
$payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date);
|
$payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date);
|
||||||
|
|
||||||
$payment = Payment::find($id);
|
$payment = Payment::find($id);
|
||||||
@ -178,16 +223,17 @@ class PaymentController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$payment->payment_date = $payment_date;
|
$payment->payment_date = $payment_date;
|
||||||
$payment->payment_number = $request->payment_number;
|
$payment->payment_number = $number_attributes['payment_number'];
|
||||||
$payment->user_id = $request->user_id;
|
$payment->user_id = $request->user_id;
|
||||||
$payment->invoice_id = $request->invoice_id;
|
$payment->invoice_id = $request->invoice_id;
|
||||||
$payment->payment_mode = $request->payment_mode;
|
$payment->payment_method_id = $request->payment_method_id;
|
||||||
$payment->amount = $request->amount;
|
$payment->amount = $request->amount;
|
||||||
$payment->notes = $request->notes;
|
$payment->notes = $request->notes;
|
||||||
$payment->save();
|
$payment->save();
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'payment' => $payment,
|
'payment' => $payment,
|
||||||
|
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash),
|
||||||
'success' => true
|
'success' => true
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -249,4 +295,27 @@ class PaymentController extends Controller
|
|||||||
'success' => true
|
'success' => true
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function sendPayment(Request $request)
|
||||||
|
{
|
||||||
|
$payment = Payment::findOrFail($request->id);
|
||||||
|
|
||||||
|
$data['payment'] = $payment->toArray();
|
||||||
|
$userId = $data['payment']['user_id'];
|
||||||
|
$data['user'] = User::find($userId)->toArray();
|
||||||
|
$data['company'] = Company::find($payment->company_id);
|
||||||
|
$email = $data['user']['email'];
|
||||||
|
|
||||||
|
if (!$email) {
|
||||||
|
return response()->json([
|
||||||
|
'error' => 'user_email_does_not_exist'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
\Mail::to($email)->send(new PaymentPdf($data));
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
119
app/Http/Controllers/PaymentMethodController.php
Normal file
119
app/Http/Controllers/PaymentMethodController.php
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater\Http\Controllers;
|
||||||
|
|
||||||
|
use Crater\PaymentMethod;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Crater\Http\Requests\PaymentMethodRequest;
|
||||||
|
|
||||||
|
class PaymentMethodController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$paymentMethods = PaymentMethod::whereCompany($request->header('company'))
|
||||||
|
->latest()
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'paymentMethods' => $paymentMethods
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function store(PaymentMethodRequest $request)
|
||||||
|
{
|
||||||
|
$paymentMethod = new PaymentMethod;
|
||||||
|
$paymentMethod->name = $request->name;
|
||||||
|
$paymentMethod->company_id = $request->header('company');
|
||||||
|
$paymentMethod->save();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'paymentMethod' => $paymentMethod
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*
|
||||||
|
* @param \Crater\PaymentMethod $paymentMethod
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function show(PaymentMethod $paymentMethod)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*
|
||||||
|
* @param \Crater\PaymentMethod $paymentMethod
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function edit(PaymentMethod $paymentMethod)
|
||||||
|
{
|
||||||
|
return response()->json([
|
||||||
|
'paymentMethod' => $paymentMethod
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Crater\PaymentMethod $paymentMethod
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function update(PaymentMethodRequest $request, PaymentMethod $paymentMethod)
|
||||||
|
{
|
||||||
|
$paymentMethod->name = $request->name;
|
||||||
|
$paymentMethod->company_id = $request->header('company');
|
||||||
|
$paymentMethod->save();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'paymentMethod' => $paymentMethod
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*
|
||||||
|
* @param \Crater\PaymentMethod $paymentMethod
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function destroy(PaymentMethod $paymentMethod)
|
||||||
|
{
|
||||||
|
$payments = $paymentMethod->payments;
|
||||||
|
|
||||||
|
if ($payments->count() > 0) {
|
||||||
|
return response()->json([
|
||||||
|
'error' => 'payments_attached'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentMethod->delete();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => 'Payment method deleted successfully'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,9 +4,18 @@ namespace Crater\Http\Controllers;
|
|||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Crater\Setting;
|
use Crater\Setting;
|
||||||
|
use Crater\Mail\TestMail;
|
||||||
|
use Mail;
|
||||||
|
|
||||||
class SettingsController extends Controller
|
class SettingsController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrive App Version.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
public function getAppVersion(Request $request)
|
public function getAppVersion(Request $request)
|
||||||
{
|
{
|
||||||
$version = Setting::getSetting('version');
|
$version = Setting::getSetting('version');
|
||||||
@ -16,4 +25,18 @@ class SettingsController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testEmailConfig(Request $request)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'to' => 'required|email',
|
||||||
|
'subject' => 'required',
|
||||||
|
'message' => 'required'
|
||||||
|
]);
|
||||||
|
|
||||||
|
Mail::to($request->to)->send(new TestMail($request->subject, $request->message));
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
119
app/Http/Controllers/UnitController.php
Normal file
119
app/Http/Controllers/UnitController.php
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater\Http\Controllers;
|
||||||
|
|
||||||
|
use Crater\Unit;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Crater\Http\Requests\UnitRequest;
|
||||||
|
|
||||||
|
class UnitController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$units = Unit::whereCompany($request->header('company'))
|
||||||
|
->latest()
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'units' => $units
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function store(UnitRequest $request)
|
||||||
|
{
|
||||||
|
$unit = new Unit;
|
||||||
|
$unit->name = $request->name;
|
||||||
|
$unit->company_id = $request->header('company');
|
||||||
|
$unit->save();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'unit' => $unit
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*
|
||||||
|
* @param \Crater\Unit $unit
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function show(Unit $unit)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*
|
||||||
|
* @param \Crater\Unit $unit
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function edit(Unit $unit)
|
||||||
|
{
|
||||||
|
return response()->json([
|
||||||
|
'unit' => $unit
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Crater\Unit $unit
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function update(UnitRequest $request, Unit $unit)
|
||||||
|
{
|
||||||
|
$unit->name = $request->name;
|
||||||
|
$unit->company_id = $request->header('company');
|
||||||
|
$unit->save();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'unit' => $unit
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*
|
||||||
|
* @param \Crater\Unit $unit
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function destroy(Unit $unit)
|
||||||
|
{
|
||||||
|
$items = $unit->items;
|
||||||
|
|
||||||
|
if ($items->count() > 0) {
|
||||||
|
return response()->json([
|
||||||
|
'error' => 'items_attached'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$unit->delete();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => 'Unit deleted successfully'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,23 +2,81 @@
|
|||||||
|
|
||||||
namespace Crater\Http\Controllers;
|
namespace Crater\Http\Controllers;
|
||||||
|
|
||||||
|
use Crater\Setting;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Crater\Space\Updater;
|
use Crater\Space\Updater;
|
||||||
use Crater\Space\SiteApi;
|
use Crater\Space\SiteApi;
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
|
||||||
class UpdateController extends Controller
|
class UpdateController extends Controller
|
||||||
{
|
{
|
||||||
public function update(Request $request)
|
|
||||||
|
public function download(Request $request)
|
||||||
{
|
{
|
||||||
set_time_limit(600); // 10 minutes
|
$request->validate([
|
||||||
|
'version' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
$json = Updater::update($request->installed, $request->version);
|
$path = Updater::download($request->version);
|
||||||
|
|
||||||
return response()->json($json);
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'path' => $path
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unzip(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'path' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$path = Updater::unzip($request->path);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'path' => $path
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'error' => $e->getMessage()
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function copyFiles(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'path' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$path = Updater::copyFiles($request->path);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'path' => $path
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function migrate(Request $request)
|
||||||
|
{
|
||||||
|
Updater::migrateUpdate();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function finishUpdate(Request $request)
|
public function finishUpdate(Request $request)
|
||||||
{
|
{
|
||||||
|
$request->validate([
|
||||||
|
'installed' => 'required',
|
||||||
|
'version' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
$json = Updater::finishUpdate($request->installed, $request->version);
|
$json = Updater::finishUpdate($request->installed, $request->version);
|
||||||
|
|
||||||
return response()->json($json);
|
return response()->json($json);
|
||||||
@ -28,7 +86,7 @@ class UpdateController extends Controller
|
|||||||
{
|
{
|
||||||
set_time_limit(600); // 10 minutes
|
set_time_limit(600); // 10 minutes
|
||||||
|
|
||||||
$json = Updater::checkForUpdate();
|
$json = Updater::checkForUpdate(Setting::getSetting('version'));
|
||||||
|
|
||||||
return response()->json($json);
|
return response()->json($json);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,8 @@ use Crater\User;
|
|||||||
use Crater\Currency;
|
use Crater\Currency;
|
||||||
use Crater\Setting;
|
use Crater\Setting;
|
||||||
use Crater\Item;
|
use Crater\Item;
|
||||||
|
use Crater\PaymentMethod;
|
||||||
|
use Crater\Unit;
|
||||||
use Crater\TaxType;
|
use Crater\TaxType;
|
||||||
use DB;
|
use DB;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
@ -46,10 +48,18 @@ class UsersController extends Controller
|
|||||||
$request->header('company')
|
$request->header('company')
|
||||||
);
|
);
|
||||||
|
|
||||||
$items = Item::all();
|
$items = Item::with('taxes')->get();
|
||||||
|
|
||||||
$taxTypes = TaxType::latest()->get();
|
$taxTypes = TaxType::latest()->get();
|
||||||
|
|
||||||
|
$paymentMethods = PaymentMethod::whereCompany($request->header('company'))
|
||||||
|
->latest()
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$units = Unit::whereCompany($request->header('company'))
|
||||||
|
->latest()
|
||||||
|
->get();
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'user' => $user,
|
'user' => $user,
|
||||||
'customers' => $customers,
|
'customers' => $customers,
|
||||||
@ -61,6 +71,8 @@ class UsersController extends Controller
|
|||||||
'items' => $items,
|
'items' => $items,
|
||||||
'taxTypes' => $taxTypes,
|
'taxTypes' => $taxTypes,
|
||||||
'moment_date_format' => $moment_date_format,
|
'moment_date_format' => $moment_date_format,
|
||||||
|
'paymentMethods' => $paymentMethods,
|
||||||
|
'units' => $units,
|
||||||
'fiscal_year' => $fiscal_year,
|
'fiscal_year' => $fiscal_year,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,6 @@ class EstimatesRequest extends FormRequest
|
|||||||
$rules = [
|
$rules = [
|
||||||
'estimate_date' => 'required',
|
'estimate_date' => 'required',
|
||||||
'expiry_date' => 'required',
|
'expiry_date' => 'required',
|
||||||
'estimate_number' => 'required|unique:estimates,estimate_number',
|
|
||||||
'user_id' => 'required',
|
'user_id' => 'required',
|
||||||
'discount' => 'required',
|
'discount' => 'required',
|
||||||
'discount_val' => 'required',
|
'discount_val' => 'required',
|
||||||
@ -41,10 +40,6 @@ class EstimatesRequest extends FormRequest
|
|||||||
'items.*.price' => 'required'
|
'items.*.price' => 'required'
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($this->getMethod() == 'PUT') {
|
|
||||||
$rules['estimate_number'] = $rules['estimate_number'].','.$this->get('id');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,6 @@ class InvoicesRequest extends FormRequest
|
|||||||
$rules = [
|
$rules = [
|
||||||
'invoice_date' => 'required',
|
'invoice_date' => 'required',
|
||||||
'due_date' => 'required',
|
'due_date' => 'required',
|
||||||
'invoice_number' => 'required|unique:invoices,invoice_number',
|
|
||||||
'user_id' => 'required',
|
'user_id' => 'required',
|
||||||
'discount' => 'required',
|
'discount' => 'required',
|
||||||
'discount_val' => 'required',
|
'discount_val' => 'required',
|
||||||
@ -41,10 +40,6 @@ class InvoicesRequest extends FormRequest
|
|||||||
'items.*.price' => 'required'
|
'items.*.price' => 'required'
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($this->getMethod() == 'PUT') {
|
|
||||||
$rules['invoice_number'] = $rules['invoice_number'].','.$this->get('id');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,12 +40,9 @@ class MailEnvironmentRequest extends FormRequest
|
|||||||
case 'mailgun':
|
case 'mailgun':
|
||||||
return [
|
return [
|
||||||
'mail_driver' => 'required|string',
|
'mail_driver' => 'required|string',
|
||||||
'mail_host' => 'required|string',
|
|
||||||
'mail_port' => 'required',
|
|
||||||
'mail_mailgun_domain' => 'required|string',
|
'mail_mailgun_domain' => 'required|string',
|
||||||
'mail_mailgun_secret' => 'required|string',
|
'mail_mailgun_secret' => 'required|string',
|
||||||
'mail_mailgun_endpoint' => 'required|string',
|
'mail_mailgun_endpoint' => 'required|string',
|
||||||
'mail_encryption' => 'required|string',
|
|
||||||
'from_name' => 'required|string',
|
'from_name' => 'required|string',
|
||||||
'from_mail' => 'required|string',
|
'from_mail' => 'required|string',
|
||||||
];
|
];
|
||||||
|
|||||||
40
app/Http/Requests/PaymentMethodRequest.php
Normal file
40
app/Http/Requests/PaymentMethodRequest.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class PaymentMethodRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'name' => 'required|unique:payment_methods,name'
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($this->getMethod() == 'PUT') {
|
||||||
|
$data['name'] = [
|
||||||
|
'required',
|
||||||
|
Rule::unique('payment_methods')->ignore($this->route('payment_method'), 'id')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,15 +24,10 @@ class PaymentRequest extends FormRequest
|
|||||||
{
|
{
|
||||||
$rules = [
|
$rules = [
|
||||||
'payment_date' => 'required',
|
'payment_date' => 'required',
|
||||||
'payment_number' => 'required|unique:payments,payment_number',
|
|
||||||
'user_id' => 'required',
|
'user_id' => 'required',
|
||||||
'amount' => 'required',
|
'amount' => 'required',
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($this->getMethod() == 'PUT') {
|
|
||||||
$rules['payment_number'] = $rules['payment_number'].','.$this->route('payment');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ class ProfileRequest extends FormRequest
|
|||||||
case 'POST':
|
case 'POST':
|
||||||
return [
|
return [
|
||||||
'name' => 'required',
|
'name' => 'required',
|
||||||
'password' => 'required',
|
'password' => 'required|min:8',
|
||||||
'address_street_1' => 'max:255',
|
'address_street_1' => 'max:255',
|
||||||
'address_street_2' => 'max:255',
|
'address_street_2' => 'max:255',
|
||||||
'email' => [
|
'email' => [
|
||||||
|
|||||||
40
app/Http/Requests/UnitRequest.php
Normal file
40
app/Http/Requests/UnitRequest.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class UnitRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'name' => 'required|unique:units,name'
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($this->getMethod() == 'PUT') {
|
||||||
|
$data['name'] = [
|
||||||
|
'required',
|
||||||
|
Rule::unique('units')->ignore($this->route('unit'), 'id')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -66,10 +66,14 @@ class Invoice extends Model
|
|||||||
'formattedDueDate'
|
'formattedDueDate'
|
||||||
];
|
];
|
||||||
|
|
||||||
public static function getNextInvoiceNumber()
|
public static function getNextInvoiceNumber($value)
|
||||||
{
|
{
|
||||||
// Get the last created order
|
// Get the last created order
|
||||||
$lastOrder = Invoice::orderBy('created_at', 'desc')->first();
|
$lastOrder = Invoice::where('invoice_number', 'LIKE', $value . '-%')
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
|
||||||
if (!$lastOrder) {
|
if (!$lastOrder) {
|
||||||
// We get here if there is no order at all
|
// We get here if there is no order at all
|
||||||
// If there is no number set it to 0, which will be 1 at the end.
|
// If there is no number set it to 0, which will be 1 at the end.
|
||||||
@ -143,10 +147,15 @@ class Invoice extends Model
|
|||||||
|
|
||||||
public function getInvoiceNumAttribute()
|
public function getInvoiceNumAttribute()
|
||||||
{
|
{
|
||||||
$position = $this->strposX($this->invoice_number, "-", 2) + 1;
|
$position = $this->strposX($this->invoice_number, "-", 1) + 1;
|
||||||
return substr($this->invoice_number, $position);
|
return substr($this->invoice_number, $position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getInvoicePrefixAttribute () {
|
||||||
|
$prefix = explode("-", $this->invoice_number)[0];
|
||||||
|
return $prefix;
|
||||||
|
}
|
||||||
|
|
||||||
public function getFormattedCreatedAtAttribute($value)
|
public function getFormattedCreatedAtAttribute($value)
|
||||||
{
|
{
|
||||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id);
|
$dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id);
|
||||||
|
|||||||
19
app/Item.php
19
app/Item.php
@ -24,19 +24,24 @@ class Item extends Model
|
|||||||
'formattedCreatedAt'
|
'formattedCreatedAt'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function unit()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Unit::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function scopeWhereSearch($query, $search)
|
public function scopeWhereSearch($query, $search)
|
||||||
{
|
{
|
||||||
return $query->where('name', 'LIKE', '%'.$search.'%');
|
return $query->where('items.name', 'LIKE', '%'.$search.'%');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scopeWherePrice($query, $price)
|
public function scopeWherePrice($query, $price)
|
||||||
{
|
{
|
||||||
return $query->where('price', $price);
|
return $query->where('items.price', $price);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scopeWhereUnit($query, $unit)
|
public function scopeWhereUnit($query, $unit_id)
|
||||||
{
|
{
|
||||||
return $query->where('unit', $unit);
|
return $query->where('items.unit_id', $unit_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scopeWhereOrder($query, $orderByField, $orderBy)
|
public function scopeWhereOrder($query, $orderByField, $orderBy)
|
||||||
@ -56,8 +61,8 @@ class Item extends Model
|
|||||||
$query->wherePrice($filters->get('price'));
|
$query->wherePrice($filters->get('price'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($filters->get('unit')) {
|
if ($filters->get('unit_id')) {
|
||||||
$query->whereUnit($filters->get('unit'));
|
$query->whereUnit($filters->get('unit_id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($filters->get('orderByField') || $filters->get('orderBy')) {
|
if ($filters->get('orderByField') || $filters->get('orderBy')) {
|
||||||
@ -80,7 +85,7 @@ class Item extends Model
|
|||||||
|
|
||||||
public function scopeWhereCompany($query, $company_id)
|
public function scopeWhereCompany($query, $company_id)
|
||||||
{
|
{
|
||||||
$query->where('company_id', $company_id);
|
$query->where('items.company_id', $company_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function invoiceItems()
|
public function invoiceItems()
|
||||||
|
|||||||
@ -6,7 +6,6 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
|||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
use Crater\Listeners\Updates\Listener;
|
use Crater\Listeners\Updates\Listener;
|
||||||
use Crater\Listeners\Updates\v2\Version200;
|
|
||||||
use Crater\Events\UpdateFinished;
|
use Crater\Events\UpdateFinished;
|
||||||
use Crater\Setting;
|
use Crater\Setting;
|
||||||
use Crater\Address;
|
use Crater\Address;
|
||||||
|
|||||||
64
app/Listeners/Updates/v2/Version210.php
Normal file
64
app/Listeners/Updates/v2/Version210.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater\Listeners\Updates\v2;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Crater\Events\UpdateFinished;
|
||||||
|
use Crater\Listeners\Updates\Listener;
|
||||||
|
use Crater\Setting;
|
||||||
|
use Crater\CompanySetting;
|
||||||
|
|
||||||
|
class Version210 extends Listener
|
||||||
|
{
|
||||||
|
const VERSION = '2.1.0';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param object $event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle(UpdateFinished $event)
|
||||||
|
{
|
||||||
|
if ($this->isListenerFired($event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add initial auto generate value
|
||||||
|
$this->addAutoGenerateSettings();
|
||||||
|
|
||||||
|
// Update Crater app version
|
||||||
|
Setting::setSetting('version', static::VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addAutoGenerateSettings()
|
||||||
|
{
|
||||||
|
$settings = [
|
||||||
|
'invoice_auto_generate' => 'YES',
|
||||||
|
'invoice_prefix' => 'INV',
|
||||||
|
'estimate_prefix' => 'EST',
|
||||||
|
'estimate_auto_generate' => 'YES',
|
||||||
|
'payment_prefix' => 'PAY',
|
||||||
|
'payment_auto_generate' => 'YES'
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($settings as $key => $value) {
|
||||||
|
CompanySetting::setSetting(
|
||||||
|
$key,
|
||||||
|
$value,
|
||||||
|
auth()->user()->company->id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
162
app/Listeners/Updates/v3/Version300.php
Normal file
162
app/Listeners/Updates/v3/Version300.php
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater\Listeners\Updates\v3;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Crater\Setting;
|
||||||
|
use Crater\Unit;
|
||||||
|
use Crater\PaymentMethod;
|
||||||
|
use Crater\Currency;
|
||||||
|
use Crater\Payment;
|
||||||
|
use Crater\Item;
|
||||||
|
use Crater\User;
|
||||||
|
use Crater\Listeners\Updates\Listener;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
|
||||||
|
class Version300 extends Listener
|
||||||
|
{
|
||||||
|
const VERSION = '3.0.0';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param object $event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle($event)
|
||||||
|
{
|
||||||
|
if ($this->isListenerFired($event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->changeMigrations();
|
||||||
|
|
||||||
|
$this->addSeederData();
|
||||||
|
|
||||||
|
$this->databaseChanges();
|
||||||
|
|
||||||
|
$this->changeMigrations(true);
|
||||||
|
|
||||||
|
Setting::setSetting('version', static::VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function changeMigrations($removeColumn = false)
|
||||||
|
{
|
||||||
|
if ($removeColumn) {
|
||||||
|
\Schema::table('items', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('unit');
|
||||||
|
});
|
||||||
|
|
||||||
|
\Schema::table('payments', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('payment_mode');
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
\Schema::create('units', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('name');
|
||||||
|
$table->integer('company_id')->unsigned()->nullable();
|
||||||
|
$table->foreign('company_id')->references('id')->on('companies');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
|
||||||
|
\Schema::table('items', function (Blueprint $table) {
|
||||||
|
$table->integer('unit_id')->unsigned()->nullable();
|
||||||
|
$table->foreign('unit_id')->references('id')->on('units')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
|
||||||
|
\Schema::create('payment_methods', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('name');
|
||||||
|
$table->integer('company_id')->unsigned()->nullable();
|
||||||
|
$table->foreign('company_id')->references('id')->on('companies');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
|
||||||
|
\Schema::table('payments', function (Blueprint $table) {
|
||||||
|
$table->string('unique_hash')->nullable();
|
||||||
|
$table->integer('payment_method_id')->unsigned()->nullable();
|
||||||
|
$table->foreign('payment_method_id')->references('id')->on('payment_methods')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addSeederData()
|
||||||
|
{
|
||||||
|
$company_id = User::where('role', 'admin')->first()->company_id;
|
||||||
|
|
||||||
|
Unit::create(['name' => 'box', 'company_id' => $company_id]);
|
||||||
|
Unit::create(['name' => 'cm', 'company_id' => $company_id]);
|
||||||
|
Unit::create(['name' => 'dz', 'company_id' => $company_id]);
|
||||||
|
Unit::create(['name' => 'ft', 'company_id' => $company_id]);
|
||||||
|
Unit::create(['name' => 'g', 'company_id' => $company_id]);
|
||||||
|
Unit::create(['name' => 'in', 'company_id' => $company_id]);
|
||||||
|
Unit::create(['name' => 'kg', 'company_id' => $company_id]);
|
||||||
|
Unit::create(['name' => 'km', 'company_id' => $company_id]);
|
||||||
|
Unit::create(['name' => 'lb', 'company_id' => $company_id]);
|
||||||
|
Unit::create(['name' => 'mg', 'company_id' => $company_id]);
|
||||||
|
Unit::create(['name' => 'pc', 'company_id' => $company_id]);
|
||||||
|
|
||||||
|
PaymentMethod::create(['name' => 'Cash', 'company_id' => $company_id]);
|
||||||
|
PaymentMethod::create(['name' => 'Check', 'company_id' => $company_id]);
|
||||||
|
PaymentMethod::create(['name' => 'Credit Card', 'company_id' => $company_id]);
|
||||||
|
PaymentMethod::create(['name' => 'Bank Transfer', 'company_id' => $company_id]);
|
||||||
|
|
||||||
|
Currency::create([
|
||||||
|
'name' => 'Serbian Dinar',
|
||||||
|
'code' => 'RSD',
|
||||||
|
'symbol' => 'RSD',
|
||||||
|
'precision' => '2',
|
||||||
|
'thousand_separator' => '.',
|
||||||
|
'decimal_separator' => ','
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function databaseChanges()
|
||||||
|
{
|
||||||
|
$payments = Payment::all();
|
||||||
|
|
||||||
|
if ($payments) {
|
||||||
|
foreach ($payments as $payment) {
|
||||||
|
$payment->unique_hash = str_random(60);
|
||||||
|
$payment->save();
|
||||||
|
|
||||||
|
$paymentMethod = PaymentMethod::where('name', $payment->payment_mode)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($paymentMethod) {
|
||||||
|
$payment->payment_method_id = $paymentMethod->id;
|
||||||
|
$payment->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$items = Item::all();
|
||||||
|
|
||||||
|
if ($items) {
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$unit = Unit::where('name', $item->unit)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($unit) {
|
||||||
|
$item->unit_id = $unit->id;
|
||||||
|
$item->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
app/Listeners/Updates/v3/Version310.php
Normal file
52
app/Listeners/Updates/v3/Version310.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater\Listeners\Updates\v3;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Crater\Listeners\Updates\Listener;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Crater\Events\UpdateFinished;
|
||||||
|
use Crater\Setting;
|
||||||
|
use Crater\Currency;
|
||||||
|
use Schema;
|
||||||
|
use Artisan;
|
||||||
|
|
||||||
|
class Version310 extends Listener
|
||||||
|
{
|
||||||
|
const VERSION = '3.1.0';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param UpdateFinished $event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle(UpdateFinished $event)
|
||||||
|
{
|
||||||
|
if ($this->isListenerFired($event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Currency::firstOrCreate(
|
||||||
|
[
|
||||||
|
'name' => 'Kyrgyzstani som',
|
||||||
|
'code' => 'KGS'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Kyrgyzstani som',
|
||||||
|
'code' => 'KGS',
|
||||||
|
'symbol' => 'С̲ ',
|
||||||
|
'precision' => '2',
|
||||||
|
'thousand_separator' => '.',
|
||||||
|
'decimal_separator' => ','
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
Artisan::call('migrate', ['--force' => true]);
|
||||||
|
|
||||||
|
// Update Crater app version
|
||||||
|
Setting::setSetting('version', static::VERSION);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,17 +12,14 @@ class EstimatePdf extends Mailable
|
|||||||
|
|
||||||
public $data = [];
|
public $data = [];
|
||||||
|
|
||||||
public $notificationEmail = '';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new message instance.
|
* Create a new message instance.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct($data, $notificationEmail)
|
public function __construct($data)
|
||||||
{
|
{
|
||||||
$this->data = $data;
|
$this->data = $data;
|
||||||
$this->notificationEmail = $notificationEmail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,6 +29,9 @@ class EstimatePdf extends Mailable
|
|||||||
*/
|
*/
|
||||||
public function build()
|
public function build()
|
||||||
{
|
{
|
||||||
return $this->from($this->notificationEmail)->markdown('emails.send.estimate', ['data', $this->data]);
|
$company = $this->data['company']['name'];
|
||||||
|
|
||||||
|
return $this->subject("Estimate from $company")
|
||||||
|
->markdown('emails.send.estimate', ['data', $this->data]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,8 @@ class EstimateViewed extends Mailable
|
|||||||
public function build()
|
public function build()
|
||||||
{
|
{
|
||||||
$email = $this->data['user']['email'];
|
$email = $this->data['user']['email'];
|
||||||
return $this->from($email)->markdown('emails.viewed.estimate', ['data', $this->data]);
|
$name = $this->data['user']['name'];
|
||||||
|
return $this->from($email, $name)
|
||||||
|
->markdown('emails.viewed.estimate', ['data', $this->data]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,23 +6,20 @@ use Illuminate\Mail\Mailable;
|
|||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
|
||||||
class invoicePdf extends Mailable
|
class InvoicePdf extends Mailable
|
||||||
{
|
{
|
||||||
use Queueable, SerializesModels;
|
use Queueable, SerializesModels;
|
||||||
|
|
||||||
public $data = [];
|
public $data = [];
|
||||||
|
|
||||||
public $notificationEmail = '';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new message instance.
|
* Create a new message instance.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct($data, $notificationEmail)
|
public function __construct($data)
|
||||||
{
|
{
|
||||||
$this->data = $data;
|
$this->data = $data;
|
||||||
$this->notificationEmail = $notificationEmail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,6 +29,9 @@ class invoicePdf extends Mailable
|
|||||||
*/
|
*/
|
||||||
public function build()
|
public function build()
|
||||||
{
|
{
|
||||||
return $this->from($this->notificationEmail)->markdown('emails.send.invoice', ['data', $this->data]);
|
$company = $this->data['company']['name'];
|
||||||
|
|
||||||
|
return $this->subject("Invoice from $company")
|
||||||
|
->markdown('emails.send.invoice', ['data', $this->data]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,6 +31,8 @@ class InvoiceViewed extends Mailable
|
|||||||
public function build()
|
public function build()
|
||||||
{
|
{
|
||||||
$email = $this->data['user']['email'];
|
$email = $this->data['user']['email'];
|
||||||
return $this->from($email)->markdown('emails.viewed.invoice', ['data', $this->data]);
|
$name = $this->data['user']['name'];
|
||||||
|
return $this->from($email, $name)
|
||||||
|
->markdown('emails.viewed.invoice', ['data', $this->data]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
38
app/Mail/PaymentPdf.php
Normal file
38
app/Mail/PaymentPdf.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class PaymentPdf extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $data = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($data)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the message.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function build()
|
||||||
|
{
|
||||||
|
$company = $this->data['company']['name'];
|
||||||
|
|
||||||
|
return $this->subject("Payment from $company")
|
||||||
|
->markdown('emails.send.payment', ['data', $this->data]);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
app/Mail/TestMail.php
Normal file
38
app/Mail/TestMail.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
namespace Crater\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
|
||||||
|
class TestMail extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
public $subject;
|
||||||
|
public $message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*
|
||||||
|
* @param $subject
|
||||||
|
* @param $message
|
||||||
|
*/
|
||||||
|
public function __construct($subject, $message)
|
||||||
|
{
|
||||||
|
$this->subject = $subject;
|
||||||
|
$this->message = $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the message.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function build()
|
||||||
|
{
|
||||||
|
return $this->subject($this->subject)->markdown('emails.test')->with([
|
||||||
|
'my_message' => $this->message
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ use Crater\User;
|
|||||||
use Crater\Invoice;
|
use Crater\Invoice;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Crater\PaymentMethod;
|
||||||
|
|
||||||
class Payment extends Model
|
class Payment extends Model
|
||||||
{
|
{
|
||||||
@ -19,9 +20,11 @@ class Payment extends Model
|
|||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'user_id',
|
'user_id',
|
||||||
'invoice_id',
|
'invoice_id',
|
||||||
|
'payment_method_id',
|
||||||
'payment_date',
|
'payment_date',
|
||||||
'company_id',
|
'company_id',
|
||||||
'notes',
|
'notes',
|
||||||
|
'unique_hash',
|
||||||
'payment_number',
|
'payment_number',
|
||||||
'payment_mode',
|
'payment_mode',
|
||||||
'amount'
|
'amount'
|
||||||
@ -32,10 +35,34 @@ class Payment extends Model
|
|||||||
'formattedPaymentDate'
|
'formattedPaymentDate'
|
||||||
];
|
];
|
||||||
|
|
||||||
public static function getNextPaymentNumber()
|
|
||||||
|
private function strposX($haystack, $needle, $number)
|
||||||
|
{
|
||||||
|
if ($number == '1') {
|
||||||
|
return strpos($haystack, $needle);
|
||||||
|
} elseif ($number > '1') {
|
||||||
|
return strpos(
|
||||||
|
$haystack,
|
||||||
|
$needle,
|
||||||
|
$this->strposX($haystack, $needle, $number - 1) + strlen($needle)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return error_log('Error: Value for parameter $number is out of range');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPaymentNumAttribute()
|
||||||
|
{
|
||||||
|
$position = $this->strposX($this->payment_number, "-", 1) + 1;
|
||||||
|
return substr($this->payment_number, $position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getNextPaymentNumber($value)
|
||||||
{
|
{
|
||||||
// Get the last created order
|
// Get the last created order
|
||||||
$payment = Payment::orderBy('created_at', 'desc')->first();
|
$payment = Payment::where('payment_number', 'LIKE', $value . '-%')
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->first();
|
||||||
if (!$payment) {
|
if (!$payment) {
|
||||||
// We get here if there is no order at all
|
// We get here if there is no order at all
|
||||||
// If there is no number set it to 0, which will be 1 at the end.
|
// If there is no number set it to 0, which will be 1 at the end.
|
||||||
@ -54,6 +81,12 @@ class Payment extends Model
|
|||||||
return sprintf('%06d', intval($number) + 1);
|
return sprintf('%06d', intval($number) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPaymentPrefixAttribute ()
|
||||||
|
{
|
||||||
|
$prefix= explode("-",$this->payment_number)[0];
|
||||||
|
return $prefix;
|
||||||
|
}
|
||||||
|
|
||||||
public function invoice()
|
public function invoice()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Invoice::class);
|
return $this->belongsTo(Invoice::class);
|
||||||
@ -64,6 +97,11 @@ class Payment extends Model
|
|||||||
return $this->belongsTo(User::class);
|
return $this->belongsTo(User::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function paymentMethod()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(PaymentMethod::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function getFormattedCreatedAtAttribute($value)
|
public function getFormattedCreatedAtAttribute($value)
|
||||||
{
|
{
|
||||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id);
|
$dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id);
|
||||||
@ -92,9 +130,9 @@ class Payment extends Model
|
|||||||
return $query->where('payments.payment_number', 'LIKE', '%'.$paymentNumber.'%');
|
return $query->where('payments.payment_number', 'LIKE', '%'.$paymentNumber.'%');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scopePaymentMode($query, $paymentMode)
|
public function scopePaymentMethod($query, $paymentMethodId)
|
||||||
{
|
{
|
||||||
return $query->where('payments.payment_mode', $paymentMode);
|
return $query->where('payments.payment_method_id', $paymentMethodId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scopeApplyFilters($query, array $filters)
|
public function scopeApplyFilters($query, array $filters)
|
||||||
@ -109,8 +147,8 @@ class Payment extends Model
|
|||||||
$query->paymentNumber($filters->get('payment_number'));
|
$query->paymentNumber($filters->get('payment_number'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($filters->get('payment_mode')) {
|
if ($filters->get('payment_method_id')) {
|
||||||
$query->paymentMode($filters->get('payment_mode'));
|
$query->paymentMethod($filters->get('payment_method_id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($filters->get('customer_id')) {
|
if ($filters->get('customer_id')) {
|
||||||
|
|||||||
25
app/PaymentMethod.php
Normal file
25
app/PaymentMethod.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class PaymentMethod extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = ['name', 'company_id'];
|
||||||
|
|
||||||
|
public function payments()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Payment::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function company()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Company::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeWhereCompany($query, $company_id)
|
||||||
|
{
|
||||||
|
$query->where('company_id', $company_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Crater\Providers;
|
namespace Crater\Providers;
|
||||||
|
|
||||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||||
@ -9,6 +10,9 @@ use Crater\Listeners\Updates\v1\Version110;
|
|||||||
use Crater\Listeners\Updates\v2\Version200;
|
use Crater\Listeners\Updates\v2\Version200;
|
||||||
use Crater\Listeners\Updates\v2\Version201;
|
use Crater\Listeners\Updates\v2\Version201;
|
||||||
use Crater\Listeners\Updates\v2\Version202;
|
use Crater\Listeners\Updates\v2\Version202;
|
||||||
|
use Crater\Listeners\Updates\v2\Version210;
|
||||||
|
use Crater\Listeners\Updates\v3\Version300;
|
||||||
|
use Crater\Listeners\Updates\v3\Version310;
|
||||||
|
|
||||||
class EventServiceProvider extends ServiceProvider
|
class EventServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
@ -23,6 +27,9 @@ class EventServiceProvider extends ServiceProvider
|
|||||||
Version200::class,
|
Version200::class,
|
||||||
Version201::class,
|
Version201::class,
|
||||||
Version202::class,
|
Version202::class,
|
||||||
|
Version210::class,
|
||||||
|
Version300::class,
|
||||||
|
Version310::class,
|
||||||
],
|
],
|
||||||
Registered::class => [
|
Registered::class => [
|
||||||
SendEmailVerificationNotification::class,
|
SendEmailVerificationNotification::class,
|
||||||
|
|||||||
@ -38,7 +38,7 @@ class EnvironmentManager
|
|||||||
'DB_PORT='.config('database.connections.'.config('database.default').'.port')."\n".
|
'DB_PORT='.config('database.connections.'.config('database.default').'.port')."\n".
|
||||||
'DB_DATABASE='.config('database.connections.'.config('database.default').'.database')."\n".
|
'DB_DATABASE='.config('database.connections.'.config('database.default').'.database')."\n".
|
||||||
'DB_USERNAME='.config('database.connections.'.config('database.default').'.username')."\n".
|
'DB_USERNAME='.config('database.connections.'.config('database.default').'.username')."\n".
|
||||||
'DB_PASSWORD='.config('database.connections.'.config('database.default').'.password')."\n\n";
|
'DB_PASSWORD="'.config('database.connections.'.config('database.default').'.password')."\"\n\n";
|
||||||
|
|
||||||
$newDatabaseData =
|
$newDatabaseData =
|
||||||
'DB_CONNECTION='.$request->database_connection."\n".
|
'DB_CONNECTION='.$request->database_connection."\n".
|
||||||
@ -46,7 +46,7 @@ class EnvironmentManager
|
|||||||
'DB_PORT='.$request->database_port."\n".
|
'DB_PORT='.$request->database_port."\n".
|
||||||
'DB_DATABASE='.$request->database_name."\n".
|
'DB_DATABASE='.$request->database_name."\n".
|
||||||
'DB_USERNAME='.$request->database_username."\n".
|
'DB_USERNAME='.$request->database_username."\n".
|
||||||
'DB_PASSWORD='.$request->database_password."\n\n";
|
'DB_PASSWORD="'.$request->database_password."\"\n\n";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ class EnvironmentManager
|
|||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'error' => $e->getMessage()
|
'error_message' => $e->getMessage()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,24 +2,44 @@
|
|||||||
namespace Crater\Space;
|
namespace Crater\Space;
|
||||||
|
|
||||||
use File;
|
use File;
|
||||||
use ZipArchive;
|
|
||||||
use Artisan;
|
use Artisan;
|
||||||
use GuzzleHttp\Exception\RequestException;
|
use GuzzleHttp\Exception\RequestException;
|
||||||
use Crater\Space\SiteApi;
|
|
||||||
use Crater\Events\UpdateFinished;
|
use Crater\Events\UpdateFinished;
|
||||||
use Crater\Setting;
|
use ZipArchive;
|
||||||
use Illuminate\Http\Request;
|
|
||||||
|
|
||||||
class Updater
|
class Updater
|
||||||
{
|
{
|
||||||
use SiteApi;
|
use SiteApi;
|
||||||
|
|
||||||
public static function update($installed, $version)
|
public static function checkForUpdate($installed_version)
|
||||||
|
{
|
||||||
|
$data = null;
|
||||||
|
if(env('APP_ENV') === 'development')
|
||||||
|
{
|
||||||
|
$url = 'https://craterapp.com/downloads/check/latest/'. $installed_version . '?type=update&is_dev=1';
|
||||||
|
} else {
|
||||||
|
$url = 'https://craterapp.com/downloads/check/latest/'. $installed_version . '?type=update';
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = static::getRemote($url, ['timeout' => 100, 'track_redirects' => true]);
|
||||||
|
|
||||||
|
if ($response && ($response->getStatusCode() == 200)) {
|
||||||
|
$data = $response->getBody()->getContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_decode($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function download($new_version)
|
||||||
{
|
{
|
||||||
$data = null;
|
$data = null;
|
||||||
$path = null;
|
$path = null;
|
||||||
|
|
||||||
$url = 'https://craterapp.com/downloads/file/'.$version.'?type=update';
|
if (env('APP_ENV') === 'development') {
|
||||||
|
$url = 'https://craterapp.com/downloads/file/' . $new_version . '?type=update&is_dev=1';
|
||||||
|
} else {
|
||||||
|
$url = 'https://craterapp.com/downloads/file/' . $new_version . '?type=update';
|
||||||
|
}
|
||||||
|
|
||||||
$response = static::getRemote($url, ['timeout' => 100, 'track_redirects' => true]);
|
$response = static::getRemote($url, ['timeout' => 100, 'track_redirects' => true]);
|
||||||
|
|
||||||
@ -39,66 +59,68 @@ class Updater
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create temp directory
|
// Create temp directory
|
||||||
$path = 'temp-' . md5(mt_rand());
|
$temp_dir = storage_path('app/temp-' . md5(mt_rand()));
|
||||||
$path2 = 'temp2-' . md5(mt_rand());
|
|
||||||
$temp_path = storage_path('app') . '/' . $path;
|
|
||||||
$temp_path2 = storage_path('app') . '/' . $path2;
|
|
||||||
|
|
||||||
if (!File::isDirectory($temp_path)) {
|
if (!File::isDirectory($temp_dir)) {
|
||||||
File::makeDirectory($temp_path);
|
File::makeDirectory($temp_dir);
|
||||||
File::makeDirectory($temp_path2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
$zip_file_path = $temp_dir . '/upload.zip';
|
||||||
|
|
||||||
$file = $temp_path . '/upload.zip';
|
|
||||||
|
|
||||||
// Add content to the Zip file
|
// Add content to the Zip file
|
||||||
$uploaded = is_int(file_put_contents($file, $data)) ? true : false;
|
$uploaded = is_int(file_put_contents($zip_file_path, $data)) ? true : false;
|
||||||
|
|
||||||
if (!$uploaded) {
|
if (!$uploaded) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $zip_file_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function unzip($zip_file_path)
|
||||||
|
{
|
||||||
|
if(!file_exists($zip_file_path)) {
|
||||||
|
throw new \Exception('Zip file not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
$temp_extract_dir = storage_path('app/temp2-' . md5(mt_rand()));
|
||||||
|
|
||||||
|
if (!File::isDirectory($temp_extract_dir)) {
|
||||||
|
File::makeDirectory($temp_extract_dir);
|
||||||
|
}
|
||||||
// Unzip the file
|
// Unzip the file
|
||||||
$zip = new ZipArchive();
|
$zip = new ZipArchive();
|
||||||
|
|
||||||
if ($zip->open($file)) {
|
if ($zip->open($zip_file_path)) {
|
||||||
$zip->extractTo($temp_path2);
|
$zip->extractTo($temp_extract_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
$zip->close();
|
$zip->close();
|
||||||
|
|
||||||
// Delete zip file
|
// Delete zip file
|
||||||
File::delete($file);
|
File::delete($zip_file_path);
|
||||||
|
|
||||||
if (!File::copyDirectory($temp_path2.'/Crater', base_path())) {
|
return $temp_extract_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function copyFiles($temp_extract_dir)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!File::copyDirectory($temp_extract_dir . '/Crater', base_path())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete temp directory
|
// Delete temp directory
|
||||||
File::deleteDirectory($temp_path);
|
File::deleteDirectory($temp_extract_dir);
|
||||||
File::deleteDirectory($temp_path2);
|
|
||||||
|
|
||||||
return [
|
return true;
|
||||||
'success' => true,
|
|
||||||
'error' => false,
|
|
||||||
'data' => []
|
|
||||||
];
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
|
|
||||||
if (File::isDirectory($temp_path)) {
|
|
||||||
// Delete temp directory
|
|
||||||
File::deleteDirectory($temp_path);
|
|
||||||
File::deleteDirectory($temp_path2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
public static function migrateUpdate()
|
||||||
'success' => false,
|
{
|
||||||
'error' => 'Update error',
|
Artisan::call('migrate --force');
|
||||||
'data' => []
|
|
||||||
];
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function finishUpdate($installed, $version)
|
public static function finishUpdate($installed, $version)
|
||||||
@ -112,17 +134,4 @@ class Updater
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function checkForUpdate()
|
|
||||||
{
|
|
||||||
$data = null;
|
|
||||||
$url = 'https://craterapp.com/downloads/check/latest/'. Setting::getSetting('version') . '?type=update';
|
|
||||||
|
|
||||||
$response = static::getRemote($url, ['timeout' => 100, 'track_redirects' => true]);
|
|
||||||
|
|
||||||
if ($response && ($response->getStatusCode() == 200)) {
|
|
||||||
$data = $response->getBody()->getContents();
|
|
||||||
}
|
|
||||||
|
|
||||||
return json_decode($data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,10 +41,14 @@ function clean_slug($string)
|
|||||||
* @param $money
|
* @param $money
|
||||||
* @return formated_money
|
* @return formated_money
|
||||||
*/
|
*/
|
||||||
function format_money_pdf($money)
|
function format_money_pdf($money, $currency = null)
|
||||||
{
|
{
|
||||||
$money = $money / 100;
|
$money = $money / 100;
|
||||||
|
|
||||||
|
if (!$currency) {
|
||||||
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', 1));
|
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', 1));
|
||||||
|
}
|
||||||
|
|
||||||
$format_money = number_format(
|
$format_money = number_format(
|
||||||
$money,
|
$money,
|
||||||
$currency->precision,
|
$currency->precision,
|
||||||
|
|||||||
26
app/Unit.php
Normal file
26
app/Unit.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Crater\Item;
|
||||||
|
|
||||||
|
class Unit extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = ['name', 'company_id'];
|
||||||
|
|
||||||
|
public function items()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Item::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function company()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Company::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeWhereCompany($query, $company_id)
|
||||||
|
{
|
||||||
|
$query->where('company_id', $company_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,6 +9,7 @@ use carbon\carbon;
|
|||||||
use Crater\MemberLoan;
|
use Crater\MemberLoan;
|
||||||
use Crater\Address;
|
use Crater\Address;
|
||||||
use Crater\Payment;
|
use Crater\Payment;
|
||||||
|
use Crater\Expense;
|
||||||
use Crater\Company;
|
use Crater\Company;
|
||||||
use Crater\Notifications\MailResetPasswordNotification;
|
use Crater\Notifications\MailResetPasswordNotification;
|
||||||
use Spatie\MediaLibrary\HasMedia\HasMedia;
|
use Spatie\MediaLibrary\HasMedia\HasMedia;
|
||||||
@ -105,6 +106,11 @@ class User extends Authenticatable implements HasMedia
|
|||||||
return $this->hasMany(Address::class);
|
return $this->hasMany(Address::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function expenses()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Expense::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function billingAddress()
|
public function billingAddress()
|
||||||
{
|
{
|
||||||
return $this->hasOne(Address::class)->where('type', Address::BILLING_TYPE);
|
return $this->hasOne(Address::class)->where('type', Address::BILLING_TYPE);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "laravel/laravel",
|
"name": "bytefury/crater",
|
||||||
"description": "The Laravel Framework.",
|
"description": "Free & Open Source Invoice App for Freelancers & Small Businesses. https://craterapp.com",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"framework",
|
"framework",
|
||||||
"laravel"
|
"laravel"
|
||||||
@ -9,6 +9,7 @@
|
|||||||
"type": "project",
|
"type": "project",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.2",
|
"php": "^7.2",
|
||||||
|
"aws/aws-sdk-php": "^3.137",
|
||||||
"barryvdh/laravel-dompdf": "^0.8.1",
|
"barryvdh/laravel-dompdf": "^0.8.1",
|
||||||
"doctrine/dbal": "^2.10",
|
"doctrine/dbal": "^2.10",
|
||||||
"fideloper/proxy": "^4.0",
|
"fideloper/proxy": "^4.0",
|
||||||
@ -53,11 +54,20 @@
|
|||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"initial-setup": [
|
||||||
|
"test -f .env || (cp .env.example .env; php artisan key:generate 2>/dev/null; exit 0)"
|
||||||
|
],
|
||||||
|
"pre-install-cmd": [
|
||||||
|
"@initial-setup"
|
||||||
|
],
|
||||||
|
"pre-update-cmd": [
|
||||||
|
"@initial-setup"
|
||||||
|
],
|
||||||
"post-root-package-install": [
|
"post-root-package-install": [
|
||||||
"php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
"@initial-setup"
|
||||||
],
|
],
|
||||||
"post-create-project-cmd": [
|
"post-create-project-cmd": [
|
||||||
"php artisan key:generate --ansi"
|
"@initial-setup"
|
||||||
],
|
],
|
||||||
"post-autoload-dump": [
|
"post-autoload-dump": [
|
||||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||||
|
|||||||
1715
composer.lock
generated
1715
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,6 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'version' => '2.0.2',
|
'version' => '3.1.0',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
244
config/dompdf.php
Normal file
244
config/dompdf.php
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return array(
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Settings
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Set some default values. It is possible to add all defines that can be set
|
||||||
|
| in dompdf_config.inc.php. You can also override the entire config file.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'show_warnings' => false, // Throw an Exception on warnings from dompdf
|
||||||
|
'orientation' => 'portrait',
|
||||||
|
'defines' => array(
|
||||||
|
/**
|
||||||
|
* The location of the DOMPDF font directory
|
||||||
|
*
|
||||||
|
* The location of the directory where DOMPDF will store fonts and font metrics
|
||||||
|
* Note: This directory must exist and be writable by the webserver process.
|
||||||
|
* *Please note the trailing slash.*
|
||||||
|
*
|
||||||
|
* Notes regarding fonts:
|
||||||
|
* Additional .afm font metrics can be added by executing load_font.php from command line.
|
||||||
|
*
|
||||||
|
* Only the original "Base 14 fonts" are present on all pdf viewers. Additional fonts must
|
||||||
|
* be embedded in the pdf file or the PDF may not display correctly. This can significantly
|
||||||
|
* increase file size unless font subsetting is enabled. Before embedding a font please
|
||||||
|
* review your rights under the font license.
|
||||||
|
*
|
||||||
|
* Any font specification in the source HTML is translated to the closest font available
|
||||||
|
* in the font directory.
|
||||||
|
*
|
||||||
|
* The pdf standard "Base 14 fonts" are:
|
||||||
|
* Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique,
|
||||||
|
* Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique,
|
||||||
|
* Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic,
|
||||||
|
* Symbol, ZapfDingbats.
|
||||||
|
*/
|
||||||
|
"font_dir" => storage_path('fonts/'), // advised by dompdf (https://github.com/dompdf/dompdf/pull/782)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location of the DOMPDF font cache directory
|
||||||
|
*
|
||||||
|
* This directory contains the cached font metrics for the fonts used by DOMPDF.
|
||||||
|
* This directory can be the same as DOMPDF_FONT_DIR
|
||||||
|
*
|
||||||
|
* Note: This directory must exist and be writable by the webserver process.
|
||||||
|
*/
|
||||||
|
"font_cache" => storage_path('fonts/'),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location of a temporary directory.
|
||||||
|
*
|
||||||
|
* The directory specified must be writeable by the webserver process.
|
||||||
|
* The temporary directory is required to download remote images and when
|
||||||
|
* using the PFDLib back end.
|
||||||
|
*/
|
||||||
|
"temp_dir" => sys_get_temp_dir(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ==== IMPORTANT ====
|
||||||
|
*
|
||||||
|
* dompdf's "chroot": Prevents dompdf from accessing system files or other
|
||||||
|
* files on the webserver. All local files opened by dompdf must be in a
|
||||||
|
* subdirectory of this directory. DO NOT set it to '/' since this could
|
||||||
|
* allow an attacker to use dompdf to read any files on the server. This
|
||||||
|
* should be an absolute path.
|
||||||
|
* This is only checked on command line call by dompdf.php, but not by
|
||||||
|
* direct class use like:
|
||||||
|
* $dompdf = new DOMPDF(); $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output();
|
||||||
|
*/
|
||||||
|
"chroot" => realpath(base_path()),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to enable font subsetting or not.
|
||||||
|
*/
|
||||||
|
"enable_font_subsetting" => false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The PDF rendering backend to use
|
||||||
|
*
|
||||||
|
* Valid settings are 'PDFLib', 'CPDF' (the bundled R&OS PDF class), 'GD' and
|
||||||
|
* 'auto'. 'auto' will look for PDFLib and use it if found, or if not it will
|
||||||
|
* fall back on CPDF. 'GD' renders PDFs to graphic files. {@link
|
||||||
|
* Canvas_Factory} ultimately determines which rendering class to instantiate
|
||||||
|
* based on this setting.
|
||||||
|
*
|
||||||
|
* Both PDFLib & CPDF rendering backends provide sufficient rendering
|
||||||
|
* capabilities for dompdf, however additional features (e.g. object,
|
||||||
|
* image and font support, etc.) differ between backends. Please see
|
||||||
|
* {@link PDFLib_Adapter} for more information on the PDFLib backend
|
||||||
|
* and {@link CPDF_Adapter} and lib/class.pdf.php for more information
|
||||||
|
* on CPDF. Also see the documentation for each backend at the links
|
||||||
|
* below.
|
||||||
|
*
|
||||||
|
* The GD rendering backend is a little different than PDFLib and
|
||||||
|
* CPDF. Several features of CPDF and PDFLib are not supported or do
|
||||||
|
* not make any sense when creating image files. For example,
|
||||||
|
* multiple pages are not supported, nor are PDF 'objects'. Have a
|
||||||
|
* look at {@link GD_Adapter} for more information. GD support is
|
||||||
|
* experimental, so use it at your own risk.
|
||||||
|
*
|
||||||
|
* @link http://www.pdflib.com
|
||||||
|
* @link http://www.ros.co.nz/pdf
|
||||||
|
* @link http://www.php.net/image
|
||||||
|
*/
|
||||||
|
"pdf_backend" => "CPDF",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDFlib license key
|
||||||
|
*
|
||||||
|
* If you are using a licensed, commercial version of PDFlib, specify
|
||||||
|
* your license key here. If you are using PDFlib-Lite or are evaluating
|
||||||
|
* the commercial version of PDFlib, comment out this setting.
|
||||||
|
*
|
||||||
|
* @link http://www.pdflib.com
|
||||||
|
*
|
||||||
|
* If pdflib present in web server and auto or selected explicitely above,
|
||||||
|
* a real license code must exist!
|
||||||
|
*/
|
||||||
|
//"DOMPDF_PDFLIB_LICENSE" => "your license key here",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* html target media view which should be rendered into pdf.
|
||||||
|
* List of types and parsing rules for future extensions:
|
||||||
|
* http://www.w3.org/TR/REC-html40/types.html
|
||||||
|
* screen, tty, tv, projection, handheld, print, braille, aural, all
|
||||||
|
* Note: aural is deprecated in CSS 2.1 because it is replaced by speech in CSS 3.
|
||||||
|
* Note, even though the generated pdf file is intended for print output,
|
||||||
|
* the desired content might be different (e.g. screen or projection view of html file).
|
||||||
|
* Therefore allow specification of content here.
|
||||||
|
*/
|
||||||
|
"default_media_type" => "screen",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default paper size.
|
||||||
|
*
|
||||||
|
* North America standard is "letter"; other countries generally "a4"
|
||||||
|
*
|
||||||
|
* @see CPDF_Adapter::PAPER_SIZES for valid sizes ('letter', 'legal', 'A4', etc.)
|
||||||
|
*/
|
||||||
|
"default_paper_size" => "a4",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default font family
|
||||||
|
*
|
||||||
|
* Used if no suitable fonts can be found. This must exist in the font folder.
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
"default_font" => "DejaVu Sans",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Image DPI setting
|
||||||
|
*
|
||||||
|
* This setting determines the default DPI setting for images and fonts. The
|
||||||
|
* DPI may be overridden for inline images by explictly setting the
|
||||||
|
* image's width & height style attributes (i.e. if the image's native
|
||||||
|
* width is 600 pixels and you specify the image's width as 72 points,
|
||||||
|
* the image will have a DPI of 600 in the rendered PDF. The DPI of
|
||||||
|
* background images can not be overridden and is controlled entirely
|
||||||
|
* via this parameter.
|
||||||
|
*
|
||||||
|
* For the purposes of DOMPDF, pixels per inch (PPI) = dots per inch (DPI).
|
||||||
|
* If a size in html is given as px (or without unit as image size),
|
||||||
|
* this tells the corresponding size in pt.
|
||||||
|
* This adjusts the relative sizes to be similar to the rendering of the
|
||||||
|
* html page in a reference browser.
|
||||||
|
*
|
||||||
|
* In pdf, always 1 pt = 1/72 inch
|
||||||
|
*
|
||||||
|
* Rendering resolution of various browsers in px per inch:
|
||||||
|
* Windows Firefox and Internet Explorer:
|
||||||
|
* SystemControl->Display properties->FontResolution: Default:96, largefonts:120, custom:?
|
||||||
|
* Linux Firefox:
|
||||||
|
* about:config *resolution: Default:96
|
||||||
|
* (xorg screen dimension in mm and Desktop font dpi settings are ignored)
|
||||||
|
*
|
||||||
|
* Take care about extra font/image zoom factor of browser.
|
||||||
|
*
|
||||||
|
* In images, <img> size in pixel attribute, img css style, are overriding
|
||||||
|
* the real image dimension in px for rendering.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
"dpi" => 96,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable inline PHP
|
||||||
|
*
|
||||||
|
* If this setting is set to true then DOMPDF will automatically evaluate
|
||||||
|
* inline PHP contained within <script type="text/php"> ... </script> tags.
|
||||||
|
*
|
||||||
|
* Enabling this for documents you do not trust (e.g. arbitrary remote html
|
||||||
|
* pages) is a security risk. Set this option to false if you wish to process
|
||||||
|
* untrusted documents.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
"enable_php" => false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable inline Javascript
|
||||||
|
*
|
||||||
|
* If this setting is set to true then DOMPDF will automatically insert
|
||||||
|
* JavaScript code contained within <script type="text/javascript"> ... </script> tags.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
"enable_javascript" => true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable remote file access
|
||||||
|
*
|
||||||
|
* If this setting is set to true, DOMPDF will access remote sites for
|
||||||
|
* images and CSS files as required.
|
||||||
|
* This is required for part of test case www/test/image_variants.html through www/examples.php
|
||||||
|
*
|
||||||
|
* Attention!
|
||||||
|
* This can be a security risk, in particular in combination with DOMPDF_ENABLE_PHP and
|
||||||
|
* allowing remote access to dompdf.php or on allowing remote html code to be passed to
|
||||||
|
* $dompdf = new DOMPDF(, $dompdf->load_html(...,
|
||||||
|
* This allows anonymous users to download legally doubtful internet content which on
|
||||||
|
* tracing back appears to being downloaded by your server, or allows malicious php code
|
||||||
|
* in remote html pages to be executed by your server with your account privileges.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
"enable_remote" => true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ratio applied to the fonts height to be more like browsers' line height
|
||||||
|
*/
|
||||||
|
"font_height_ratio" => 1.1,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the more-than-experimental HTML5 Lib parser
|
||||||
|
*/
|
||||||
|
"enable_html5_parser" => true,
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
);
|
||||||
36
database/migrations/2017_04_11_064308_create_units_table.php
Normal file
36
database/migrations/2017_04_11_064308_create_units_table.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class CreateUnitsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
if (!Schema::hasTable('units')) {
|
||||||
|
Schema::create('units', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('name');
|
||||||
|
$table->integer('company_id')->unsigned()->nullable();
|
||||||
|
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('units');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -21,6 +21,8 @@ class CreateItemsTable extends Migration
|
|||||||
$table->unsignedBigInteger('price');
|
$table->unsignedBigInteger('price');
|
||||||
$table->integer('company_id')->unsigned()->nullable();
|
$table->integer('company_id')->unsigned()->nullable();
|
||||||
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
||||||
|
$table->integer('unit_id')->unsigned()->nullable();
|
||||||
|
$table->foreign('unit_id')->references('id')->on('units')->onDelete('cascade');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,6 @@ class CreateExpenseCategoriesTable extends Migration
|
|||||||
*/
|
*/
|
||||||
public function down()
|
public function down()
|
||||||
{
|
{
|
||||||
Schema::dropIfExists('expenses_categories');
|
Schema::dropIfExists('expense_categories');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,6 @@ class CreateAddressesTable extends Migration
|
|||||||
*/
|
*/
|
||||||
public function down()
|
public function down()
|
||||||
{
|
{
|
||||||
Schema::dropIfExists('address');
|
Schema::dropIfExists('addresses');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class CreatePaymentMethodsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
if (!Schema::hasTable('payment_methods')) {
|
||||||
|
Schema::create('payment_methods', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('name');
|
||||||
|
$table->integer('company_id')->unsigned()->nullable();
|
||||||
|
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('payment_methods');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,16 +16,18 @@ class CreatePaymentsTable extends Migration
|
|||||||
Schema::create('payments', function (Blueprint $table) {
|
Schema::create('payments', function (Blueprint $table) {
|
||||||
$table->bigIncrements('id');
|
$table->bigIncrements('id');
|
||||||
$table->string('payment_number');
|
$table->string('payment_number');
|
||||||
$table->string('payment_mode')->nullable();
|
|
||||||
$table->date('payment_date');
|
$table->date('payment_date');
|
||||||
$table->text('notes')->nullable();
|
$table->text('notes')->nullable();
|
||||||
$table->unsignedBigInteger('amount');
|
$table->unsignedBigInteger('amount');
|
||||||
|
$table->string('unique_hash')->nullable();
|
||||||
$table->integer('user_id')->unsigned();
|
$table->integer('user_id')->unsigned();
|
||||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||||
$table->integer('invoice_id')->unsigned()->nullable();
|
$table->integer('invoice_id')->unsigned()->nullable();
|
||||||
$table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
|
$table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
|
||||||
$table->integer('company_id')->unsigned()->nullable();
|
$table->integer('company_id')->unsigned()->nullable();
|
||||||
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
||||||
|
$table->integer('payment_method_id')->unsigned()->nullable();
|
||||||
|
$table->foreign('payment_method_id')->references('id')->on('payment_methods')->onDelete('cascade');
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,9 +20,9 @@ class CreateMediaTable extends Migration
|
|||||||
$table->string('mime_type')->nullable();
|
$table->string('mime_type')->nullable();
|
||||||
$table->string('disk');
|
$table->string('disk');
|
||||||
$table->unsignedInteger('size');
|
$table->unsignedInteger('size');
|
||||||
$table->json('manipulations');
|
$table->text('manipulations');
|
||||||
$table->json('custom_properties');
|
$table->text('custom_properties');
|
||||||
$table->json('responsive_images');
|
$table->text('responsive_images');
|
||||||
$table->unsignedInteger('order_column')->nullable();
|
$table->unsignedInteger('order_column')->nullable();
|
||||||
$table->nullableTimestamps();
|
$table->nullableTimestamps();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddUserIdToExpensesTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('expenses', function (Blueprint $table) {
|
||||||
|
$table->integer('user_id')->unsigned()->nullable();
|
||||||
|
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('expenses', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('paid');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -524,6 +524,22 @@ class CurrenciesTableSeeder extends Seeder
|
|||||||
'thousand_separator' => '.',
|
'thousand_separator' => '.',
|
||||||
'decimal_separator' => ','
|
'decimal_separator' => ','
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Serbian Dinar',
|
||||||
|
'code' => 'RSD',
|
||||||
|
'symbol' => 'RSD',
|
||||||
|
'precision' => '2',
|
||||||
|
'thousand_separator' => '.',
|
||||||
|
'decimal_separator' => ','
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Kyrgyzstani som',
|
||||||
|
'code' => 'KGS',
|
||||||
|
'symbol' => 'С̲ ',
|
||||||
|
'precision' => '2',
|
||||||
|
'thousand_separator' => '.',
|
||||||
|
'decimal_separator' => ','
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($currencies as $currency) {
|
foreach ($currencies as $currency) {
|
||||||
|
|||||||
20
database/seeds/PaymentMethodSeeder.php
Normal file
20
database/seeds/PaymentMethodSeeder.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Crater\PaymentMethod;
|
||||||
|
|
||||||
|
class PaymentMethodSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
PaymentMethod::create(['name' => 'Cash', 'company_id' => 1]);
|
||||||
|
PaymentMethod::create(['name' => 'Check', 'company_id' => 1]);
|
||||||
|
PaymentMethod::create(['name' => 'Credit Card', 'company_id' => 1]);
|
||||||
|
PaymentMethod::create(['name' => 'Bank Transfer', 'company_id' => 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
27
database/seeds/UnitSeeder.php
Normal file
27
database/seeds/UnitSeeder.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Crater\Unit;
|
||||||
|
|
||||||
|
class UnitSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
Unit::create(['name' => 'box', 'company_id' => 1]);
|
||||||
|
Unit::create(['name' => 'cm', 'company_id' => 1]);
|
||||||
|
Unit::create(['name' => 'dz', 'company_id' => 1]);
|
||||||
|
Unit::create(['name' => 'ft', 'company_id' => 1]);
|
||||||
|
Unit::create(['name' => 'g', 'company_id' => 1]);
|
||||||
|
Unit::create(['name' => 'in', 'company_id' => 1]);
|
||||||
|
Unit::create(['name' => 'kg', 'company_id' => 1]);
|
||||||
|
Unit::create(['name' => 'km', 'company_id' => 1]);
|
||||||
|
Unit::create(['name' => 'lb', 'company_id' => 1]);
|
||||||
|
Unit::create(['name' => 'mg', 'company_id' => 1]);
|
||||||
|
Unit::create(['name' => 'pc', 'company_id' => 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
40
docker-compose.yaml.example
Normal file
40
docker-compose.yaml.example
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
version: '3.1'
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
web:
|
||||||
|
image: nginx
|
||||||
|
depends_on:
|
||||||
|
- php
|
||||||
|
ports:
|
||||||
|
- 8080:80
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
- app:/app
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
php:
|
||||||
|
build: .
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
expose:
|
||||||
|
- 9000
|
||||||
|
volumes:
|
||||||
|
- app:/app
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: mariadb
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- db:/var/lib/mysql
|
||||||
|
environment:
|
||||||
|
MYSQL_USER: crater
|
||||||
|
MYSQL_PASSWORD: crater
|
||||||
|
MYSQL_DATABASE: crater
|
||||||
|
MYSQL_ROOT_PASSWORD: crater
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
app:
|
||||||
|
db:
|
||||||
|
|
||||||
53
nginx.conf
Normal file
53
nginx.conf
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
worker_processes 8;
|
||||||
|
|
||||||
|
error_log /var/log/nginx/error.log warn;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 4096;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
|
access_log /var/log/nginx/access.log main;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
|
||||||
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
|
||||||
|
root /app/public;
|
||||||
|
index index.php;
|
||||||
|
charset utf-8;
|
||||||
|
|
||||||
|
access_log off;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /favicon.ico { access_log off; log_not_found off; }
|
||||||
|
location = /robots.txt { access_log off; log_not_found off; }
|
||||||
|
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Robots-Tag none;
|
||||||
|
add_header Content-Security-Policy "frame-ancestors 'self'";
|
||||||
|
|
||||||
|
location ~ \.php$ {
|
||||||
|
fastcgi_pass php:9000;
|
||||||
|
fastcgi_index index.php;
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
include /etc/nginx/fastcgi_params;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5034
package-lock.json
generated
5034
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
24
package.json
24
package.json
@ -8,19 +8,16 @@
|
|||||||
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
|
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-eslint": "^8.2.3",
|
"babel-eslint": "^8.2.6",
|
||||||
"browser-sync": "^2.26.7",
|
|
||||||
"browser-sync-webpack-plugin": "^2.0.1",
|
|
||||||
"cross-env": "^5.1",
|
"cross-env": "^5.1",
|
||||||
"css-loader": "^0.28.8",
|
"css-loader": "^0.28.8",
|
||||||
"eslint": "^4.14.0",
|
"eslint": "^4.19.1",
|
||||||
"eslint-config-standard": "^11.0.0-beta.0",
|
"eslint-config-prettier": "^6.10.1",
|
||||||
"eslint-plugin-import": "^2.11.0",
|
"eslint-loader": "^3.0.3",
|
||||||
"eslint-plugin-node": "^5.2.1",
|
"eslint-plugin-prettier": "^3.1.2",
|
||||||
"eslint-plugin-promise": "^3.6.0",
|
"eslint-plugin-vue": "^4.7.1",
|
||||||
"eslint-plugin-standard": "^3.0.1",
|
|
||||||
"eslint-plugin-vue": "^4.0.1",
|
|
||||||
"laravel-mix": "^5.0.0",
|
"laravel-mix": "^5.0.0",
|
||||||
|
"prettier": "^2.0.2",
|
||||||
"resolve-url-loader": "3.1.0",
|
"resolve-url-loader": "3.1.0",
|
||||||
"sass": "^1.22.9",
|
"sass": "^1.22.9",
|
||||||
"sass-loader": "7.*",
|
"sass-loader": "7.*",
|
||||||
@ -35,19 +32,14 @@
|
|||||||
"axios": "^0.19",
|
"axios": "^0.19",
|
||||||
"bootstrap": "^4.1.0",
|
"bootstrap": "^4.1.0",
|
||||||
"chart.js": "^2.7.3",
|
"chart.js": "^2.7.3",
|
||||||
"cross-env": "^5.1.4",
|
|
||||||
"easy-pie-chart": "^2.1.7",
|
|
||||||
"fs": "0.0.1-security",
|
|
||||||
"guid": "0.0.12",
|
"guid": "0.0.12",
|
||||||
"lodash": "^4.17.13",
|
"lodash": "^4.17.13",
|
||||||
"moment": "^2.18.1",
|
"moment": "^2.18.1",
|
||||||
"npm": "^6.4.1",
|
|
||||||
"popper.js": "^1.12.9",
|
|
||||||
"sweet-modal-vue": "^2.0.0",
|
"sweet-modal-vue": "^2.0.0",
|
||||||
"sweetalert": "^2.1.2",
|
"sweetalert": "^2.1.2",
|
||||||
"toastr": "^2.1.4",
|
"toastr": "^2.1.4",
|
||||||
"upgrade": "^1.1.0",
|
|
||||||
"v-money": "^0.8.1",
|
"v-money": "^0.8.1",
|
||||||
|
"v-tooltip": "^2.0.2",
|
||||||
"vue": "^2.5.17",
|
"vue": "^2.5.17",
|
||||||
"vue-avatar-cropper": "^1.0.5",
|
"vue-avatar-cropper": "^1.0.5",
|
||||||
"vue-i18n": "^8.14.0",
|
"vue-i18n": "^8.14.0",
|
||||||
|
|||||||
4
public/assets/css/crater.css
vendored
4
public/assets/css/crater.css
vendored
File diff suppressed because one or more lines are too long
1
public/assets/css/crater.css.map
Normal file
1
public/assets/css/crater.css.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"/assets/js/app.js": "/assets/js/app.js?id=36ab3529ebffd4f0624b",
|
"/assets/js/app.js": "/assets/js/app.js?id=2521d0dcc4cb4e4975a5",
|
||||||
"/assets/css/crater.css": "/assets/css/crater.css?id=108e3a8d009e7d38018c"
|
"/assets/css/crater.css": "/assets/css/crater.css?id=84a4eeb53b0e6a937e44"
|
||||||
}
|
}
|
||||||
|
|||||||
10
readme.md
10
readme.md
@ -29,7 +29,7 @@ Web Application is made using Laravel & VueJS while the Mobile Apps are built us
|
|||||||
|
|
||||||
## Mobile Apps
|
## Mobile Apps
|
||||||
- [Android](https://play.google.com/store/apps/details?id=com.craterapp.app)
|
- [Android](https://play.google.com/store/apps/details?id=com.craterapp.app)
|
||||||
- IOS - Coming Soon
|
- [IOS](https://apps.apple.com/app/id1489169767)
|
||||||
- [Source](https://github.com/bytefury/crater-mobile)
|
- [Source](https://github.com/bytefury/crater-mobile)
|
||||||
|
|
||||||
## Discord
|
## Discord
|
||||||
@ -60,8 +60,14 @@ Join the Crater discord server to discuss:
|
|||||||
## Credits
|
## Credits
|
||||||
Crater is a product of [Bytefury](https://bytefury.com)
|
Crater is a product of [Bytefury](https://bytefury.com)
|
||||||
|
|
||||||
|
**Special thanks to:**
|
||||||
|
* [Birkhoff Lee](https://github.com/BirkhoffLee)
|
||||||
|
* [Hassan A. Ba Abdullah](https://github.com/hsnapps)
|
||||||
|
|
||||||
## Translate
|
## Translate
|
||||||
Help us translate on [Transifex](https://www.transifex.com/bytefury/crater-invoice)
|
Help us translate or suggest changes to existing languages if you find any mistakes by creating a new PR.
|
||||||
|
|
||||||
|
Here's the [english-version](https://github.com/bytefury/crater/blob/master/resources/assets/js/plugins/en.json) json file which you can use as a reference.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
Crater is released under the Attribution Assurance License.
|
Crater is released under the Attribution Assurance License.
|
||||||
|
|||||||
30
resources/assets/js/bootstrap.js
vendored
30
resources/assets/js/bootstrap.js
vendored
@ -12,6 +12,7 @@ import CustomerModal from './components/base/modal/CustomerModal.vue'
|
|||||||
import TaxTypeModal from './components/base/modal/TaxTypeModal.vue'
|
import TaxTypeModal from './components/base/modal/TaxTypeModal.vue'
|
||||||
import CategoryModal from './components/base/modal/CategoryModal.vue'
|
import CategoryModal from './components/base/modal/CategoryModal.vue'
|
||||||
import money from 'v-money'
|
import money from 'v-money'
|
||||||
|
import VTooltip from 'v-tooltip'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global css plugins
|
* Global css plugins
|
||||||
@ -87,17 +88,27 @@ window.axios.interceptors.request.use(function (config) {
|
|||||||
|
|
||||||
global.axios.interceptors.response.use(undefined, function (err) {
|
global.axios.interceptors.response.use(undefined, function (err) {
|
||||||
// Do something with request error
|
// Do something with request error
|
||||||
return new Promise((resolve, reject) => {
|
if (!err.response) {
|
||||||
console.log(err.response)
|
window.toastr['error']('Network error: Please check your internet connection or wait until servers are back online')
|
||||||
if (err.response.data.error === 'invalid_credentials') {
|
console.log('Network error: Please check your internet connection.')
|
||||||
window.toastr['error']('Invalid Credentials')
|
|
||||||
}
|
|
||||||
if (err.response.data && (err.response.statusText === 'Unauthorized' || err.response.data === ' Unauthorized.')) {
|
|
||||||
store.dispatch('auth/logout', true)
|
|
||||||
} else {
|
} else {
|
||||||
throw err
|
console.log(err.response)
|
||||||
|
if (err.response.data && (err.response.statusText === 'Unauthorized' || err.response.data === ' Unauthorized.')) {
|
||||||
|
// Unauthorized and log out
|
||||||
|
window.toastr['error']((err.response.data.message) ? err.response.data.message : 'Unauthorized')
|
||||||
|
store.dispatch('auth/logout', true)
|
||||||
|
} else if (err.response.data.errors) {
|
||||||
|
// Show a notification per error
|
||||||
|
const errors = JSON.parse(JSON.stringify(err.response.data.errors))
|
||||||
|
for (const i in errors) {
|
||||||
|
window.toastr['error'](errors[i])
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
|
// Unknown error
|
||||||
|
window.toastr['error']((err.response.data.message) ? err.response.data.message : 'Unknown error occurred')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.reject(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -107,6 +118,7 @@ window.toastr = require('toastr')
|
|||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
|
Vue.use(VTooltip)
|
||||||
|
|
||||||
// register directive v-money and component <money>
|
// register directive v-money and component <money>
|
||||||
Vue.use(money, {precision: 2})
|
Vue.use(money, {precision: 2})
|
||||||
|
|||||||
71
resources/assets/js/components/base/BasePrefixInput.vue
Normal file
71
resources/assets/js/components/base/BasePrefixInput.vue
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<template>
|
||||||
|
<div class="base-prefix-input" @click="focusInput">
|
||||||
|
<font-awesome-icon v-if="icon" :icon="icon" class="icon" />
|
||||||
|
<p class="prefix-label"><span class="mr-1">{{ prefix }}</span>-</p>
|
||||||
|
<input
|
||||||
|
ref="basePrefixInput"
|
||||||
|
v-model="inputValue"
|
||||||
|
:type="type"
|
||||||
|
class="prefix-input-field"
|
||||||
|
@input="handleInput"
|
||||||
|
@change="handleChange"
|
||||||
|
@keyup="handleKeyupEnter"
|
||||||
|
@keydown="handleKeyDownEnter"
|
||||||
|
@blur="handleFocusOut"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
prefix: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number, File],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'text'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
inputValue: this.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'value' () {
|
||||||
|
this.inputValue = this.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
focusInput () {
|
||||||
|
this.$refs.basePrefixInput.focus()
|
||||||
|
},
|
||||||
|
handleInput (e) {
|
||||||
|
this.$emit('input', this.inputValue)
|
||||||
|
},
|
||||||
|
handleChange (e) {
|
||||||
|
this.$emit('change', this.inputValue)
|
||||||
|
},
|
||||||
|
handleKeyupEnter (e) {
|
||||||
|
this.$emit('keyup', this.inputValue)
|
||||||
|
},
|
||||||
|
handleKeyDownEnter (e) {
|
||||||
|
this.$emit('keydown', e, this.inputValue)
|
||||||
|
},
|
||||||
|
handleFocusOut (e) {
|
||||||
|
this.$emit('blur', this.inputValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -8,6 +8,7 @@ import BaseTextArea from './BaseTextArea.vue'
|
|||||||
import BaseSelect from './base-select/BaseSelect.vue'
|
import BaseSelect from './base-select/BaseSelect.vue'
|
||||||
import BaseLoader from './BaseLoader.vue'
|
import BaseLoader from './BaseLoader.vue'
|
||||||
import BaseCustomerSelect from './BaseCustomerSelect.vue'
|
import BaseCustomerSelect from './BaseCustomerSelect.vue'
|
||||||
|
import BasePrefixInput from './BasePrefixInput.vue'
|
||||||
|
|
||||||
import BasePopup from './popup/BasePopup.vue'
|
import BasePopup from './popup/BasePopup.vue'
|
||||||
import CustomerSelectPopup from './popup/CustomerSelectPopup.vue'
|
import CustomerSelectPopup from './popup/CustomerSelectPopup.vue'
|
||||||
@ -23,6 +24,7 @@ Vue.component('base-input', BaseInput)
|
|||||||
Vue.component('base-switch', BaseSwitch)
|
Vue.component('base-switch', BaseSwitch)
|
||||||
Vue.component('base-text-area', BaseTextArea)
|
Vue.component('base-text-area', BaseTextArea)
|
||||||
Vue.component('base-loader', BaseLoader)
|
Vue.component('base-loader', BaseLoader)
|
||||||
|
Vue.component('base-prefix-input', BasePrefixInput)
|
||||||
|
|
||||||
Vue.component('table-component', TableComponent)
|
Vue.component('table-component', TableComponent)
|
||||||
Vue.component('table-column', TableColumn)
|
Vue.component('table-column', TableColumn)
|
||||||
|
|||||||
@ -21,6 +21,9 @@ import EstimateTemplate from './EstimateTemplate'
|
|||||||
import InvoiceTemplate from './InvoiceTemplate'
|
import InvoiceTemplate from './InvoiceTemplate'
|
||||||
import CustomerModal from './CustomerModal'
|
import CustomerModal from './CustomerModal'
|
||||||
import CategoryModal from './CategoryModal'
|
import CategoryModal from './CategoryModal'
|
||||||
|
import PaymentMode from './PaymentModeModal'
|
||||||
|
import ItemUnit from './ItemUnitModal'
|
||||||
|
import MailTestModal from './MailTestModal'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -29,7 +32,10 @@ export default {
|
|||||||
EstimateTemplate,
|
EstimateTemplate,
|
||||||
InvoiceTemplate,
|
InvoiceTemplate,
|
||||||
CustomerModal,
|
CustomerModal,
|
||||||
CategoryModal
|
CategoryModal,
|
||||||
|
PaymentMode,
|
||||||
|
ItemUnit,
|
||||||
|
MailTestModal
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -55,6 +55,7 @@
|
|||||||
v-model="currency"
|
v-model="currency"
|
||||||
:options="currencies"
|
:options="currencies"
|
||||||
:searchable="true"
|
:searchable="true"
|
||||||
|
:allow-empty="false"
|
||||||
:show-labels="false"
|
:show-labels="false"
|
||||||
:placeholder="$t('customers.select_currency')"
|
:placeholder="$t('customers.select_currency')"
|
||||||
label="name"
|
label="name"
|
||||||
@ -340,6 +341,7 @@ export default {
|
|||||||
mixins: [validationMixin],
|
mixins: [validationMixin],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
isEdit: false,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
countryList: [],
|
countryList: [],
|
||||||
billingCountry: null,
|
billingCountry: null,
|
||||||
@ -398,9 +400,22 @@ export default {
|
|||||||
...mapGetters('currency', [
|
...mapGetters('currency', [
|
||||||
'defaultCurrency',
|
'defaultCurrency',
|
||||||
'currencies'
|
'currencies'
|
||||||
|
]),
|
||||||
|
...mapGetters('modal', [
|
||||||
|
'modalDataID',
|
||||||
|
'modalData',
|
||||||
|
'modalActive'
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
'modalDataID' (val) {
|
||||||
|
if (val) {
|
||||||
|
this.isEdit = true
|
||||||
|
this.setData()
|
||||||
|
} else {
|
||||||
|
this.isEdit = false
|
||||||
|
}
|
||||||
|
},
|
||||||
billingCountry () {
|
billingCountry () {
|
||||||
if (this.billingCountry) {
|
if (this.billingCountry) {
|
||||||
this.billing.country_id = this.billingCountry.id
|
this.billing.country_id = this.billingCountry.id
|
||||||
@ -418,6 +433,9 @@ export default {
|
|||||||
this.$refs.name.focus = true
|
this.$refs.name.focus = true
|
||||||
this.currency = this.defaultCurrency
|
this.currency = this.defaultCurrency
|
||||||
this.fetchCountry()
|
this.fetchCountry()
|
||||||
|
if (this.modalDataID) {
|
||||||
|
this.setData()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions('invoice', {
|
...mapActions('invoice', {
|
||||||
@ -492,6 +510,24 @@ export default {
|
|||||||
this.formData.addresses = [{...this.shipping, type: 'shipping'}]
|
this.formData.addresses = [{...this.shipping, type: 'shipping'}]
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
async setData () {
|
||||||
|
this.formData.id = this.modalData.id
|
||||||
|
this.formData.name = this.modalData.name
|
||||||
|
this.formData.email = this.modalData.email
|
||||||
|
this.formData.contact_name = this.modalData.contact_name
|
||||||
|
this.formData.phone = this.modalData.phone
|
||||||
|
this.formData.website = this.modalData.website
|
||||||
|
this.currency = this.modalData.currency
|
||||||
|
|
||||||
|
if (this.modalData.billing_address) {
|
||||||
|
this.billing = this.modalData.billing_address
|
||||||
|
this.billingCountry = this.modalData.billing_address.country
|
||||||
|
}
|
||||||
|
if (this.modalData.shipping_address) {
|
||||||
|
this.shipping = this.modalData.shipping_address
|
||||||
|
this.shippingCountry = this.modalData.shipping_address.country
|
||||||
|
}
|
||||||
|
},
|
||||||
async submitCustomerData () {
|
async submitCustomerData () {
|
||||||
this.$v.formData.$touch()
|
this.$v.formData.$touch()
|
||||||
|
|
||||||
@ -509,14 +545,23 @@ export default {
|
|||||||
this.formData.currency_id = this.defaultCurrency.id
|
this.formData.currency_id = this.defaultCurrency.id
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let response = await this.addCustomer(this.formData)
|
let response = null
|
||||||
|
if (this.modalDataID) {
|
||||||
|
response = await this.updateCustomer(this.formData)
|
||||||
|
} else {
|
||||||
|
response = await this.addCustomer(this.formData)
|
||||||
|
}
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
|
if (this.modalDataID) {
|
||||||
|
window.toastr['success'](this.$tc('customers.updated_message'))
|
||||||
|
} else {
|
||||||
window.toastr['success'](this.$tc('customers.created_message'))
|
window.toastr['success'](this.$tc('customers.created_message'))
|
||||||
|
}
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
if (this.$route.name === 'invoices.create') {
|
if (this.$route.name === 'invoices.create' || this.$route.name === 'invoices.edit') {
|
||||||
this.setInvoiceCustomer(response.data.customer.id)
|
this.setInvoiceCustomer(response.data.customer.id)
|
||||||
}
|
}
|
||||||
if (this.$route.name === 'estimates.create') {
|
if (this.$route.name === 'estimates.create' || this.$route.name === 'estimates.edit') {
|
||||||
this.setEstimateCustomer(response.data.customer.id)
|
this.setEstimateCustomer(response.data.customer.id)
|
||||||
}
|
}
|
||||||
this.resetData()
|
this.resetData()
|
||||||
|
|||||||
@ -45,14 +45,34 @@
|
|||||||
<div class="col-sm-7">
|
<div class="col-sm-7">
|
||||||
<base-select
|
<base-select
|
||||||
v-model="formData.unit"
|
v-model="formData.unit"
|
||||||
:options="units"
|
:options="itemUnits"
|
||||||
:searchable="true"
|
:searchable="true"
|
||||||
:show-labels="false"
|
:show-labels="false"
|
||||||
label="name"
|
label="name"
|
||||||
|
>
|
||||||
|
<div slot="afterList">
|
||||||
|
<button type="button" class="list-add-button" @click="addItemUnit">
|
||||||
|
<font-awesome-icon class="icon" icon="cart-plus" />
|
||||||
|
<label>{{ $t('settings.customization.items.add_item_unit') }}</label>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</base-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="isTexPerItem" class="form-group row">
|
||||||
|
<label class="col-sm-4 col-form-label input-label">{{ $t('items.taxes') }}</label>
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<base-select
|
||||||
|
v-model="formData.taxes"
|
||||||
|
:options="getTaxTypes"
|
||||||
|
:searchable="true"
|
||||||
|
:show-labels="false"
|
||||||
|
:allow-empty="true"
|
||||||
|
:multiple="true"
|
||||||
|
label="tax_name"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-4 col-form-label input-label">{{ $t('items.description') }}</label>
|
<label class="col-sm-4 col-form-label input-label">{{ $t('items.description') }}</label>
|
||||||
<div class="col-sm-7">
|
<div class="col-sm-7">
|
||||||
@ -124,11 +144,13 @@ export default {
|
|||||||
{ name: 'mg', value: 'mg' },
|
{ name: 'mg', value: 'mg' },
|
||||||
{ name: 'pc', value: 'pc' }
|
{ name: 'pc', value: 'pc' }
|
||||||
],
|
],
|
||||||
|
taxes: [],
|
||||||
formData: {
|
formData: {
|
||||||
name: null,
|
name: null,
|
||||||
price: null,
|
price: null,
|
||||||
description: null,
|
description: null,
|
||||||
unit: null
|
unit: null,
|
||||||
|
taxes: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -161,12 +183,28 @@ export default {
|
|||||||
this.formData.price = newValue * 100
|
this.formData.price = newValue * 100
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// itemUnits () {
|
||||||
|
// return this.units
|
||||||
|
// },
|
||||||
...mapGetters('modal', [
|
...mapGetters('modal', [
|
||||||
'modalDataID'
|
'modalDataID',
|
||||||
|
'modalData'
|
||||||
]),
|
]),
|
||||||
...mapGetters('item', [
|
...mapGetters('item', [
|
||||||
'getItemById'
|
'getItemById',
|
||||||
])
|
'itemUnits'
|
||||||
|
]),
|
||||||
|
...mapGetters('taxType', [
|
||||||
|
'taxTypes'
|
||||||
|
]),
|
||||||
|
isTexPerItem () {
|
||||||
|
return this.modalData.taxPerItem === 'YES'
|
||||||
|
},
|
||||||
|
getTaxTypes () {
|
||||||
|
return this.taxTypes.map(tax => {
|
||||||
|
return {...tax, tax_name: tax.name + ' (' + tax.percent + '%)'}
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
modalDataID () {
|
modalDataID () {
|
||||||
@ -179,12 +217,17 @@ export default {
|
|||||||
this.isEdit = true
|
this.isEdit = true
|
||||||
this.fetchEditData()
|
this.fetchEditData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.isEdit) {
|
||||||
|
this.loadEditData()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.$refs.name.focus = true
|
this.$refs.name.focus = true
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions('modal', [
|
...mapActions('modal', [
|
||||||
|
'openModal',
|
||||||
'closeModal',
|
'closeModal',
|
||||||
'resetModalData'
|
'resetModalData'
|
||||||
]),
|
]),
|
||||||
@ -203,7 +246,6 @@ export default {
|
|||||||
unit: null,
|
unit: null,
|
||||||
id: null
|
id: null
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$v.$reset()
|
this.$v.$reset()
|
||||||
},
|
},
|
||||||
fetchEditData () {
|
fetchEditData () {
|
||||||
@ -230,9 +272,20 @@ export default {
|
|||||||
if (this.isEdit) {
|
if (this.isEdit) {
|
||||||
response = await this.updateItem(this.formData)
|
response = await this.updateItem(this.formData)
|
||||||
} else {
|
} else {
|
||||||
response = await this.addItem(this.formData)
|
let data = {
|
||||||
|
...this.formData,
|
||||||
|
taxes: this.formData.taxes.map(tax => {
|
||||||
|
return {
|
||||||
|
tax_type_id: tax.id,
|
||||||
|
amount: ((this.formData.price * tax.percent) / 100),
|
||||||
|
percent: tax.percent,
|
||||||
|
name: tax.name,
|
||||||
|
collective_tax: 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
response = await this.addItem(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
window.toastr['success'](this.$tc('items.created_message'))
|
window.toastr['success'](this.$tc('items.created_message'))
|
||||||
this.setItem(response.data.item)
|
this.setItem(response.data.item)
|
||||||
@ -245,6 +298,12 @@ export default {
|
|||||||
}
|
}
|
||||||
window.toastr['error'](response.data.error)
|
window.toastr['error'](response.data.error)
|
||||||
},
|
},
|
||||||
|
async addItemUnit () {
|
||||||
|
this.openModal({
|
||||||
|
'title': 'Add Item Unit',
|
||||||
|
'componentName': 'ItemUnit'
|
||||||
|
})
|
||||||
|
},
|
||||||
closeItemModal () {
|
closeItemModal () {
|
||||||
this.resetFormData()
|
this.resetFormData()
|
||||||
this.closeModal()
|
this.closeModal()
|
||||||
|
|||||||
148
resources/assets/js/components/base/modal/ItemUnitModal.vue
Normal file
148
resources/assets/js/components/base/modal/ItemUnitModal.vue
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<template>
|
||||||
|
<div class="item-unit-modal">
|
||||||
|
<form action="" @submit.prevent="submitItemUnit">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-4 col-form-label input-label">{{ $t('settings.customization.items.unit_name') }} <span class="required"> *</span></label>
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<base-input
|
||||||
|
ref="name"
|
||||||
|
:invalid="$v.formData.name.$error"
|
||||||
|
v-model="formData.name"
|
||||||
|
type="text"
|
||||||
|
@input="$v.formData.name.$touch()"
|
||||||
|
/>
|
||||||
|
<div v-if="$v.formData.name.$error">
|
||||||
|
<span v-if="!$v.formData.name.required" class="form-group__message text-danger">{{ $tc('validation.required') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<base-button
|
||||||
|
:outline="true"
|
||||||
|
class="mr-3"
|
||||||
|
color="theme"
|
||||||
|
type="button"
|
||||||
|
@click="closePaymentModeModal"
|
||||||
|
>
|
||||||
|
{{ $t('general.cancel') }}
|
||||||
|
</base-button>
|
||||||
|
<base-button
|
||||||
|
:loading="isLoading"
|
||||||
|
color="theme"
|
||||||
|
icon="save"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
{{ !isEdit ? $t('general.save') : $t('general.update') }}
|
||||||
|
</base-button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapGetters } from 'vuex'
|
||||||
|
import { validationMixin } from 'vuelidate'
|
||||||
|
const { required, minLength } = require('vuelidate/lib/validators')
|
||||||
|
export default {
|
||||||
|
mixins: [validationMixin],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
isEdit: false,
|
||||||
|
isLoading: false,
|
||||||
|
formData: {
|
||||||
|
id: null,
|
||||||
|
name: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters('modal', [
|
||||||
|
'modalDataID',
|
||||||
|
'modalData',
|
||||||
|
'modalActive'
|
||||||
|
])
|
||||||
|
},
|
||||||
|
validations: {
|
||||||
|
formData: {
|
||||||
|
name: {
|
||||||
|
required,
|
||||||
|
minLength: minLength(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted () {
|
||||||
|
this.$refs.name.focus = true
|
||||||
|
if (this.modalDataID) {
|
||||||
|
this.isEdit = true
|
||||||
|
this.setData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions('modal', [
|
||||||
|
'closeModal',
|
||||||
|
'resetModalData'
|
||||||
|
]),
|
||||||
|
...mapActions('item', [
|
||||||
|
'addItemUnit',
|
||||||
|
'updateItemUnit',
|
||||||
|
'fatchItemUnit'
|
||||||
|
]),
|
||||||
|
resetFormData () {
|
||||||
|
this.formData = {
|
||||||
|
id: null,
|
||||||
|
name: null
|
||||||
|
}
|
||||||
|
this.$v.formData.$reset()
|
||||||
|
},
|
||||||
|
async submitItemUnit () {
|
||||||
|
this.$v.formData.$touch()
|
||||||
|
if (this.$v.$invalid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
this.isLoading = true
|
||||||
|
|
||||||
|
let response
|
||||||
|
|
||||||
|
if (this.isEdit) {
|
||||||
|
response = await this.updateItemUnit(this.formData)
|
||||||
|
|
||||||
|
if (response.data) {
|
||||||
|
window.toastr['success'](this.$t('settings.customization.items.item_unit_updated'))
|
||||||
|
this.closePaymentModeModal()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
window.toastr['error'](response.data.error)
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
response = await this.addItemUnit(this.formData)
|
||||||
|
if (response.data) {
|
||||||
|
this.isLoading = false
|
||||||
|
window.toastr['success'](this.$t('settings.customization.items.item_unit_added'))
|
||||||
|
this.closePaymentModeModal()
|
||||||
|
return true
|
||||||
|
} window.toastr['error'](response.data.error)
|
||||||
|
} catch (err) {
|
||||||
|
if (err.response.data.errors.name) {
|
||||||
|
this.isLoading = true
|
||||||
|
window.toastr['error'](this.$t('validation.item_unit_already_taken'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async setData () {
|
||||||
|
this.formData = {
|
||||||
|
id: this.modalData.id,
|
||||||
|
name: this.modalData.name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
closePaymentModeModal () {
|
||||||
|
this.resetModalData()
|
||||||
|
this.resetFormData()
|
||||||
|
this.closeModal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
166
resources/assets/js/components/base/modal/MailTestModal.vue
Normal file
166
resources/assets/js/components/base/modal/MailTestModal.vue
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mail-test-modal">
|
||||||
|
<form action="" @submit.prevent="onTestMailSend">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-4 col-form-label input-label">{{ $t('general.to') }} <span class="required"> *</span></label>
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<base-input
|
||||||
|
ref="to"
|
||||||
|
:invalid="$v.formData.to.$error"
|
||||||
|
v-model="formData.to"
|
||||||
|
type="text"
|
||||||
|
@input="$v.formData.to.$touch()"
|
||||||
|
/>
|
||||||
|
<div v-if="$v.formData.to.$error">
|
||||||
|
<span v-if="!$v.formData.to.required" class="form-group__message text-danger">{{ $tc('validation.required') }}</span>
|
||||||
|
<span v-if="!$v.formData.to.email" class="form-group__message text-danger"> {{ $t('validation.email_incorrect') }} </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-4 col-form-label input-label">{{ $t('general.subject') }} <span class="required"> *</span></label>
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<div class="base-input">
|
||||||
|
<base-input
|
||||||
|
:invalid="$v.formData.subject.$error"
|
||||||
|
v-model="formData.subject"
|
||||||
|
type="text"
|
||||||
|
@input="$v.formData.subject.$touch()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="$v.formData.subject.$error">
|
||||||
|
<span v-if="!$v.formData.subject.required" class="text-danger">{{ $t('validation.required') }}</span>
|
||||||
|
<span v-if="!$v.formData.subject.maxLength" class="text-danger">{{ $t('validation.subject_maxlength') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-4 col-form-label input-label">{{ $t('general.message') }}<span class="required"> *</span></label>
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<base-text-area
|
||||||
|
v-model="formData.message"
|
||||||
|
:invalid="$v.formData.message.$error"
|
||||||
|
rows="4"
|
||||||
|
cols="50"
|
||||||
|
@input="$v.formData.message.$touch()"
|
||||||
|
/>
|
||||||
|
<div v-if="$v.formData.message.$error">
|
||||||
|
<span v-if="!$v.formData.message.required" class="text-danger">{{ $t('validation.required') }}</span>
|
||||||
|
<span v-if="!$v.formData.message.maxLength" class="text-danger">{{ $t('validation.message_maxlength') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<base-button
|
||||||
|
:outline="true"
|
||||||
|
class="mr-3"
|
||||||
|
color="theme"
|
||||||
|
type="button"
|
||||||
|
@click="closeTaxModal"
|
||||||
|
>
|
||||||
|
{{ $t('general.cancel') }}
|
||||||
|
</base-button>
|
||||||
|
<base-button
|
||||||
|
:loading="isLoading"
|
||||||
|
color="theme"
|
||||||
|
icon="save"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
{{ !isEdit ? $t('general.save') : $t('general.update') }}
|
||||||
|
</base-button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapGetters } from 'vuex'
|
||||||
|
import { validationMixin } from 'vuelidate'
|
||||||
|
const { required, minLength, email, maxLength } = require('vuelidate/lib/validators')
|
||||||
|
export default {
|
||||||
|
mixins: [validationMixin],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
isEdit: false,
|
||||||
|
isLoading: false,
|
||||||
|
formData: {
|
||||||
|
to: null,
|
||||||
|
subject: null,
|
||||||
|
message: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters('modal', [
|
||||||
|
'modalDataID',
|
||||||
|
'modalData',
|
||||||
|
'modalActive'
|
||||||
|
])
|
||||||
|
},
|
||||||
|
validations: {
|
||||||
|
formData: {
|
||||||
|
to: {
|
||||||
|
required,
|
||||||
|
email
|
||||||
|
},
|
||||||
|
subject: {
|
||||||
|
required,
|
||||||
|
maxLength: maxLength(100)
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
required,
|
||||||
|
maxLength: maxLength(255)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted () {
|
||||||
|
this.$refs.to.focus = true
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions('modal', [
|
||||||
|
'closeModal',
|
||||||
|
'resetModalData'
|
||||||
|
]),
|
||||||
|
resetFormData () {
|
||||||
|
this.formData = {
|
||||||
|
to: null,
|
||||||
|
subject: null,
|
||||||
|
message: null
|
||||||
|
}
|
||||||
|
this.$v.formData.$reset()
|
||||||
|
},
|
||||||
|
async onTestMailSend () {
|
||||||
|
this.$v.formData.$touch()
|
||||||
|
|
||||||
|
if (this.$v.$invalid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isLoading = true
|
||||||
|
let response = await axios.post('/api/settings/test/mail', this.formData)
|
||||||
|
if (response.data) {
|
||||||
|
|
||||||
|
if (response.data.success) {
|
||||||
|
window.toastr['success'](this.$tc('general.send_mail_successfully'))
|
||||||
|
this.closeTaxModal()
|
||||||
|
this.isLoading = false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
window.toastr['error'](this.$tc('validation.something_went_wrong'))
|
||||||
|
this.closeTaxModal()
|
||||||
|
this.isLoading = false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
window.toastr['error'](response.data.error)
|
||||||
|
},
|
||||||
|
closeTaxModal () {
|
||||||
|
this.resetModalData()
|
||||||
|
this.resetFormData()
|
||||||
|
this.closeModal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
143
resources/assets/js/components/base/modal/PaymentModeModal.vue
Normal file
143
resources/assets/js/components/base/modal/PaymentModeModal.vue
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
<template>
|
||||||
|
<div class="payment-modes-modal">
|
||||||
|
<form action="" @submit.prevent="submitPaymentMode">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-4 col-form-label input-label">{{ $t('settings.customization.payments.mode_name') }} <span class="required"> *</span></label>
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<base-input
|
||||||
|
ref="name"
|
||||||
|
:invalid="$v.formData.name.$error"
|
||||||
|
v-model="formData.name"
|
||||||
|
type="text"
|
||||||
|
@input="$v.formData.name.$touch()"
|
||||||
|
/>
|
||||||
|
<div v-if="$v.formData.name.$error">
|
||||||
|
<span v-if="!$v.formData.name.required" class="form-group__message text-danger">{{ $tc('validation.required') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<base-button
|
||||||
|
:outline="true"
|
||||||
|
class="mr-3"
|
||||||
|
color="theme"
|
||||||
|
type="button"
|
||||||
|
@click="closePaymentModeModal"
|
||||||
|
>
|
||||||
|
{{ $t('general.cancel') }}
|
||||||
|
</base-button>
|
||||||
|
<base-button
|
||||||
|
:loading="isLoading"
|
||||||
|
color="theme"
|
||||||
|
icon="save"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
{{ !isEdit ? $t('general.save') : $t('general.update') }}
|
||||||
|
</base-button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapGetters } from 'vuex'
|
||||||
|
import { validationMixin } from 'vuelidate'
|
||||||
|
const { required, minLength } = require('vuelidate/lib/validators')
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mixins: [validationMixin],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
isEdit: false,
|
||||||
|
isLoading: false,
|
||||||
|
formData: {
|
||||||
|
id: null,
|
||||||
|
name: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters('modal', [
|
||||||
|
'modalDataID',
|
||||||
|
'modalData',
|
||||||
|
'modalActive'
|
||||||
|
])
|
||||||
|
},
|
||||||
|
validations: {
|
||||||
|
formData: {
|
||||||
|
name: {
|
||||||
|
required,
|
||||||
|
minLength: minLength(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted () {
|
||||||
|
this.$refs.name.focus = true
|
||||||
|
if (this.modalDataID) {
|
||||||
|
this.isEdit = true
|
||||||
|
this.setData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions('modal', [
|
||||||
|
'closeModal',
|
||||||
|
'resetModalData'
|
||||||
|
]),
|
||||||
|
...mapActions('payment', [
|
||||||
|
'addPaymentMode',
|
||||||
|
'updatePaymentMode'
|
||||||
|
]),
|
||||||
|
resetFormData () {
|
||||||
|
this.formData = {
|
||||||
|
id: null,
|
||||||
|
name: null
|
||||||
|
}
|
||||||
|
this.$v.formData.$reset()
|
||||||
|
},
|
||||||
|
async submitPaymentMode () {
|
||||||
|
this.$v.formData.$touch()
|
||||||
|
if (this.$v.$invalid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
this.isLoading = true
|
||||||
|
let response
|
||||||
|
if (this.isEdit) {
|
||||||
|
response = await this.updatePaymentMode(this.formData)
|
||||||
|
if (response.data) {
|
||||||
|
window.toastr['success'](this.$t('settings.customization.payments.payment_mode_updated'))
|
||||||
|
this.closePaymentModeModal()
|
||||||
|
return true
|
||||||
|
} window.toastr['error'](response.data.error)
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
response = await this.addPaymentMode(this.formData)
|
||||||
|
if (response.data) {
|
||||||
|
this.isLoading = false
|
||||||
|
window.toastr['success'](this.$t('settings.customization.payments.payment_mode_added'))
|
||||||
|
this.closePaymentModeModal()
|
||||||
|
return true
|
||||||
|
} window.toastr['error'](response.data.error)
|
||||||
|
} catch (err) {
|
||||||
|
if (err.response.data.errors.name) {
|
||||||
|
this.isLoading = true
|
||||||
|
window.toastr['error'](this.$t('validation.payment_mode_already_taken'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async setData () {
|
||||||
|
this.formData = {
|
||||||
|
id: this.modalData.id,
|
||||||
|
name: this.modalData.name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
closePaymentModeModal () {
|
||||||
|
this.resetModalData()
|
||||||
|
this.resetFormData()
|
||||||
|
this.closeModal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -124,7 +124,7 @@ export default {
|
|||||||
},
|
},
|
||||||
percent: {
|
percent: {
|
||||||
required,
|
required,
|
||||||
between: between(0.10, 100)
|
between: between(0, 100)
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
maxLength: maxLength(255)
|
maxLength: maxLength(255)
|
||||||
|
|||||||
@ -1,69 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="graph-container">
|
|
||||||
<canvas
|
|
||||||
id="graph"
|
|
||||||
ref="graph"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Chart from 'chart.js'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
labels: {
|
|
||||||
type: Array,
|
|
||||||
require: true,
|
|
||||||
default: Array
|
|
||||||
},
|
|
||||||
values: {
|
|
||||||
type: Array,
|
|
||||||
require: true,
|
|
||||||
default: Array
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted () {
|
|
||||||
let context = this.$refs.graph.getContext('2d')
|
|
||||||
let options = {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false,
|
|
||||||
legend: {
|
|
||||||
display: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = {
|
|
||||||
labels: this.labels,
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: 'My First dataset',
|
|
||||||
backgroundColor: 'rgba(79, 196, 127,0.2)',
|
|
||||||
borderColor: 'rgba(79, 196, 127,1)',
|
|
||||||
borderWidth: 1,
|
|
||||||
hoverBackgroundColor: 'rgba(79, 196, 127,0.4)',
|
|
||||||
hoverBorderColor: 'rgba(79, 196, 127,1)',
|
|
||||||
data: this.values
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
this.myBarChart = new Chart(context, {
|
|
||||||
type: 'bar',
|
|
||||||
data: data,
|
|
||||||
options: options
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
beforeDestroy () {
|
|
||||||
this.myBarChart.destroy()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.graph-container {
|
|
||||||
height: 300px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="graph-container">
|
|
||||||
<canvas
|
|
||||||
id="graph"
|
|
||||||
ref="graph"/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Chart from 'chart.js'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
labels: {
|
|
||||||
type: Array,
|
|
||||||
require: true,
|
|
||||||
default: Array
|
|
||||||
},
|
|
||||||
values: {
|
|
||||||
type: Array,
|
|
||||||
require: true,
|
|
||||||
default: Array
|
|
||||||
},
|
|
||||||
bgColors: {
|
|
||||||
type: Array,
|
|
||||||
require: true,
|
|
||||||
default: Array
|
|
||||||
},
|
|
||||||
hoverBgColors: {
|
|
||||||
type: Array,
|
|
||||||
require: true,
|
|
||||||
default: Array
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted () {
|
|
||||||
let context = this.$refs.graph.getContext('2d')
|
|
||||||
let options = {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = {
|
|
||||||
labels: this.labels,
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
data: this.values,
|
|
||||||
backgroundColor: this.bgColors,
|
|
||||||
hoverBackgroundColor: this.hoverBgColors
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
this.myDoughnutChart = new Chart(context, {
|
|
||||||
type: 'doughnut',
|
|
||||||
data: data,
|
|
||||||
options: options
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
beforeDestroy () {
|
|
||||||
this.myDoughnutChart.destroy()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.graph-container {
|
|
||||||
height: 300px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,8 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="graph-container">
|
<div class="graph-container">
|
||||||
<canvas
|
<canvas id="graph" ref="graph" />
|
||||||
id="graph"
|
|
||||||
ref="graph" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -16,55 +14,53 @@ export default {
|
|||||||
labels: {
|
labels: {
|
||||||
type: Array,
|
type: Array,
|
||||||
require: true,
|
require: true,
|
||||||
default: Array
|
default: Array,
|
||||||
},
|
},
|
||||||
values: {
|
values: {
|
||||||
type: Array,
|
type: Array,
|
||||||
require: true,
|
require: true,
|
||||||
default: Array
|
default: Array,
|
||||||
},
|
},
|
||||||
invoices: {
|
invoices: {
|
||||||
type: Array,
|
type: Array,
|
||||||
require: true,
|
require: true,
|
||||||
default: Array
|
default: Array,
|
||||||
},
|
},
|
||||||
expenses: {
|
expenses: {
|
||||||
type: Array,
|
type: Array,
|
||||||
require: true,
|
require: true,
|
||||||
default: Array
|
default: Array,
|
||||||
},
|
},
|
||||||
receipts: {
|
receipts: {
|
||||||
type: Array,
|
type: Array,
|
||||||
require: true,
|
require: true,
|
||||||
default: Array
|
default: Array,
|
||||||
},
|
},
|
||||||
income: {
|
income: {
|
||||||
type: Array,
|
type: Array,
|
||||||
require: true,
|
require: true,
|
||||||
default: Array
|
default: Array,
|
||||||
},
|
},
|
||||||
formatMoney: {
|
formatMoney: {
|
||||||
type: Function,
|
type: Function,
|
||||||
require: false,
|
require: false,
|
||||||
default: Function
|
default: Function,
|
||||||
},
|
},
|
||||||
FormatGraphMoney: {
|
FormatGraphMoney: {
|
||||||
type: Function,
|
type: Function,
|
||||||
require: false,
|
require: false,
|
||||||
default: Function
|
default: Function,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters('currency', [
|
...mapGetters('currency', ['defaultCurrency']),
|
||||||
'defaultCurrency'
|
|
||||||
])
|
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
labels(val) {
|
labels(val) {
|
||||||
this.update()
|
this.update()
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -77,13 +73,16 @@ export default {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
callbacks: {
|
callbacks: {
|
||||||
label: function (tooltipItem, data) {
|
label: function (tooltipItem, data) {
|
||||||
return self.FormatGraphMoney(tooltipItem.value, self.defaultCurrency)
|
return self.FormatGraphMoney(
|
||||||
}
|
tooltipItem.value * 100,
|
||||||
}
|
self.defaultCurrency
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
display: false
|
display: false,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
let data = {
|
let data = {
|
||||||
labels: this.labels,
|
labels: this.labels,
|
||||||
@ -107,7 +106,7 @@ export default {
|
|||||||
pointHoverBorderWidth: 2,
|
pointHoverBorderWidth: 2,
|
||||||
pointRadius: 4,
|
pointRadius: 4,
|
||||||
pointHitRadius: 10,
|
pointHitRadius: 10,
|
||||||
data: this.invoices
|
data: this.invoices.map((invoice) => invoice / 100),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Receipts',
|
label: 'Receipts',
|
||||||
@ -128,7 +127,7 @@ export default {
|
|||||||
pointHoverBorderWidth: 2,
|
pointHoverBorderWidth: 2,
|
||||||
pointRadius: 4,
|
pointRadius: 4,
|
||||||
pointHitRadius: 10,
|
pointHitRadius: 10,
|
||||||
data: this.receipts
|
data: this.receipts.map((receipt) => receipt / 100),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Expenses',
|
label: 'Expenses',
|
||||||
@ -149,7 +148,7 @@ export default {
|
|||||||
pointHoverBorderWidth: 2,
|
pointHoverBorderWidth: 2,
|
||||||
pointRadius: 4,
|
pointRadius: 4,
|
||||||
pointHitRadius: 10,
|
pointHitRadius: 10,
|
||||||
data: this.expenses
|
data: this.expenses.map((expense) => expense / 100),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Net Income',
|
label: 'Net Income',
|
||||||
@ -170,34 +169,40 @@ export default {
|
|||||||
pointHoverBorderWidth: 2,
|
pointHoverBorderWidth: 2,
|
||||||
pointRadius: 4,
|
pointRadius: 4,
|
||||||
pointHitRadius: 10,
|
pointHitRadius: 10,
|
||||||
data: this.income
|
data: this.income.map((_i) => _i / 100),
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
this.myLineChart = new Chart(context, {
|
this.myLineChart = new Chart(context, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
data: data,
|
data: data,
|
||||||
options: options
|
options: options,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
update() {
|
update() {
|
||||||
this.myLineChart.data.labels = this.labels
|
this.myLineChart.data.labels = this.labels
|
||||||
this.myLineChart.data.datasets[0].data = this.invoices
|
this.myLineChart.data.datasets[0].data = this.invoices.map(
|
||||||
this.myLineChart.data.datasets[1].data = this.receipts
|
(invoice) => invoice / 100
|
||||||
this.myLineChart.data.datasets[2].data = this.expenses
|
)
|
||||||
this.myLineChart.data.datasets[3].data = this.income
|
this.myLineChart.data.datasets[1].data = this.receipts.map(
|
||||||
|
(receipt) => receipt / 100
|
||||||
|
)
|
||||||
|
this.myLineChart.data.datasets[2].data = this.expenses.map(
|
||||||
|
(expense) => expense / 100
|
||||||
|
)
|
||||||
|
this.myLineChart.data.datasets[3].data = this.income.map((_i) => _i / 100)
|
||||||
this.myLineChart.update({
|
this.myLineChart.update({
|
||||||
lazy: true
|
lazy: true,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.myLineChart.destroy()
|
this.myLineChart.destroy()
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -1,72 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="graph-container">
|
|
||||||
<canvas
|
|
||||||
id="graph"
|
|
||||||
ref="graph" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Chart from 'chart.js'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
labels: {
|
|
||||||
type: Array,
|
|
||||||
require: true,
|
|
||||||
default: Array
|
|
||||||
},
|
|
||||||
values: {
|
|
||||||
type: Array,
|
|
||||||
require: true,
|
|
||||||
default: Array
|
|
||||||
},
|
|
||||||
bgColors: {
|
|
||||||
type: Array,
|
|
||||||
require: true,
|
|
||||||
default: Array
|
|
||||||
},
|
|
||||||
hoverBgColors: {
|
|
||||||
type: Array,
|
|
||||||
require: true,
|
|
||||||
default: Array
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted () {
|
|
||||||
let context = this.$refs.graph.getContext('2d')
|
|
||||||
|
|
||||||
let options = {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = {
|
|
||||||
labels: this.labels,
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
data: this.values,
|
|
||||||
backgroundColor: this.bgColors,
|
|
||||||
hoverBackgroundColor: this.hoverBgColors
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
this.pieChart = new Chart(context, {
|
|
||||||
type: 'pie',
|
|
||||||
data: data,
|
|
||||||
options: options
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
beforeDestroy () {
|
|
||||||
this.pieChart.destroy()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.graph-container {
|
|
||||||
height: 300px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,95 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="graph-container easy-pie-chart">
|
|
||||||
<svg width="100%" height="100%" viewBox="0 0 34 34" class="donut">
|
|
||||||
<circle :stroke-width="strokeWidth" class="donut-segment" cx="17" cy="17" r="15.91549430918954" fill="transparent" :stroke="strokeColor" stroke-dasharray="100 0" />
|
|
||||||
<circle :stroke-width="strokeWidth" :stroke="color" :stroke-dasharray="successProgress" class="donut-segment" cx="17" cy="17" r="15.91549430918954" fill="transparent" />
|
|
||||||
<!-- <g class="chart-text">
|
|
||||||
<text :style="'fill:' + color" x="48%" y="50%" class="chart-number" >
|
|
||||||
{{ progress }}
|
|
||||||
</text>
|
|
||||||
<text :style="'fill:' + color" x="73%" y="50%" class="chart-label" >
|
|
||||||
%
|
|
||||||
</text>
|
|
||||||
</g> -->
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
values: {
|
|
||||||
type: Number,
|
|
||||||
require: true,
|
|
||||||
default: 100
|
|
||||||
},
|
|
||||||
strokeWidth: {
|
|
||||||
type: Number,
|
|
||||||
require: false,
|
|
||||||
default: 1.2
|
|
||||||
},
|
|
||||||
strokeColor: {
|
|
||||||
type: String,
|
|
||||||
require: true,
|
|
||||||
default: '#eeeeee'
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
type: String,
|
|
||||||
require: true,
|
|
||||||
default: '#007dcc'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
progress: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
values (newvalue, oldvalue) {
|
|
||||||
if (newvalue !== oldvalue) {
|
|
||||||
this.setProgress()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
successProgress () {
|
|
||||||
return this.progress + ' ' + (100 - this.progress)
|
|
||||||
},
|
|
||||||
remainProgress () {
|
|
||||||
return 100 - this.progress + ' ' + this.progress
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
this.setProgress()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
setProgress () {
|
|
||||||
let self = this
|
|
||||||
for (let i = 0; i < this.values; i++) {
|
|
||||||
setTimeout(function () {
|
|
||||||
++self.progress
|
|
||||||
}, 15 * i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped>
|
|
||||||
.chart-text {
|
|
||||||
font: 6px "Montserrat", Arial, sans-serif;
|
|
||||||
fill: #000;
|
|
||||||
-moz-transform: translateY(0.25em);
|
|
||||||
-ms-transform: translateY(0.25em);
|
|
||||||
-webkit-transform: translateY(0.25em);
|
|
||||||
transform: translateY(0.5em);
|
|
||||||
}
|
|
||||||
.chart-number {
|
|
||||||
font-size: 8px;
|
|
||||||
line-height: 1;
|
|
||||||
text-anchor: middle;
|
|
||||||
}
|
|
||||||
.chart-label {
|
|
||||||
font-size: 5px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
text-anchor: middle;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -39,7 +39,12 @@ export default {
|
|||||||
|
|
||||||
formatMoney(amount, currency = 0) {
|
formatMoney(amount, currency = 0) {
|
||||||
if (!currency) {
|
if (!currency) {
|
||||||
currency = {precision: 2, thousand_separator: ',', decimal_separator: '.', symbol: '$'}
|
currency = {
|
||||||
|
precision: 2,
|
||||||
|
thousand_separator: ',',
|
||||||
|
decimal_separator: '.',
|
||||||
|
symbol: '$',
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
amount = amount / 100
|
amount = amount / 100
|
||||||
@ -52,12 +57,26 @@ export default {
|
|||||||
|
|
||||||
const negativeSign = amount < 0 ? '-' : ''
|
const negativeSign = amount < 0 ? '-' : ''
|
||||||
|
|
||||||
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(precision)).toString()
|
let i = parseInt(
|
||||||
let j = (i.length > 3) ? i.length % 3 : 0
|
(amount = Math.abs(Number(amount) || 0).toFixed(precision))
|
||||||
|
).toString()
|
||||||
|
let j = i.length > 3 ? i.length % 3 : 0
|
||||||
|
|
||||||
let moneySymbol = `<span style="font-family: sans-serif">${symbol}</span>`
|
let moneySymbol = `<span style="font-family: sans-serif">${symbol}</span>`
|
||||||
|
|
||||||
return moneySymbol + ' ' + negativeSign + (j ? i.substr(0, j) + thousand_separator : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand_separator) + (precision ? decimal_separator + Math.abs(amount - i).toFixed(precision).slice(2) : '')
|
return (
|
||||||
|
moneySymbol +
|
||||||
|
' ' +
|
||||||
|
negativeSign +
|
||||||
|
(j ? i.substr(0, j) + thousand_separator : '') +
|
||||||
|
i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand_separator) +
|
||||||
|
(precision
|
||||||
|
? decimal_separator +
|
||||||
|
Math.abs(amount - i)
|
||||||
|
.toFixed(precision)
|
||||||
|
.slice(2)
|
||||||
|
: '')
|
||||||
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
@ -65,7 +84,12 @@ export default {
|
|||||||
|
|
||||||
formatGraphMoney(amount, currency = 0) {
|
formatGraphMoney(amount, currency = 0) {
|
||||||
if (!currency) {
|
if (!currency) {
|
||||||
currency = {precision: 2, thousand_separator: ',', decimal_separator: '.', symbol: '$'}
|
currency = {
|
||||||
|
precision: 2,
|
||||||
|
thousand_separator: ',',
|
||||||
|
decimal_separator: '.',
|
||||||
|
symbol: '$',
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
amount = amount / 100
|
amount = amount / 100
|
||||||
@ -78,25 +102,76 @@ export default {
|
|||||||
|
|
||||||
const negativeSign = amount < 0 ? '-' : ''
|
const negativeSign = amount < 0 ? '-' : ''
|
||||||
|
|
||||||
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(precision)).toString()
|
let i = parseInt(
|
||||||
let j = (i.length > 3) ? i.length % 3 : 0
|
(amount = Math.abs(Number(amount) || 0).toFixed(precision))
|
||||||
|
).toString()
|
||||||
|
let j = i.length > 3 ? i.length % 3 : 0
|
||||||
|
|
||||||
let moneySymbol = `${symbol}`
|
let moneySymbol = `${symbol}`
|
||||||
|
|
||||||
return moneySymbol + ' ' + negativeSign + (j ? i.substr(0, j) + thousand_separator : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand_separator) + (precision ? decimal_separator + Math.abs(amount - i).toFixed(precision).slice(2) : '')
|
return (
|
||||||
|
moneySymbol +
|
||||||
|
' ' +
|
||||||
|
negativeSign +
|
||||||
|
(j ? i.substr(0, j) + thousand_separator : '') +
|
||||||
|
i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand_separator) +
|
||||||
|
(precision
|
||||||
|
? decimal_separator +
|
||||||
|
Math.abs(amount - i)
|
||||||
|
.toFixed(precision)
|
||||||
|
.slice(2)
|
||||||
|
: '')
|
||||||
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
checkValidUrl(url) {
|
checkValidUrl(url) {
|
||||||
let pattern = new RegExp('^(https?:\\/\\/)?' + // protocol
|
let pattern = new RegExp(
|
||||||
|
'^(https?:\\/\\/)?' + // protocol
|
||||||
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
|
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
|
||||||
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
|
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
|
||||||
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
|
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
|
||||||
'(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
|
'(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
|
||||||
'(\\#[-a-z\\d_]*)?$', 'i') // fragment locator
|
'(\\#[-a-z\\d_]*)?$',
|
||||||
|
'i'
|
||||||
|
) // fragment locator
|
||||||
|
|
||||||
return !!pattern.test(url)
|
return !!pattern.test(url)
|
||||||
|
},
|
||||||
|
|
||||||
|
fallbackCopyTextToClipboard(text) {
|
||||||
|
var textArea = document.createElement('textarea')
|
||||||
|
textArea.value = text
|
||||||
|
// Avoid scrolling to bottom
|
||||||
|
textArea.style.top = '0'
|
||||||
|
textArea.style.left = '0'
|
||||||
|
textArea.style.position = 'fixed'
|
||||||
|
document.body.appendChild(textArea)
|
||||||
|
textArea.focus()
|
||||||
|
textArea.select()
|
||||||
|
try {
|
||||||
|
var successful = document.execCommand('copy')
|
||||||
|
var msg = successful ? 'successful' : 'unsuccessful'
|
||||||
|
console.log('Fallback: Copying text command was ' + msg)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Fallback: Oops, unable to copy', err)
|
||||||
}
|
}
|
||||||
|
document.body.removeChild(textArea)
|
||||||
|
},
|
||||||
|
copyTextToClipboard(text) {
|
||||||
|
if (!navigator.clipboard) {
|
||||||
|
this.fallbackCopyTextToClipboard(text)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
navigator.clipboard.writeText(text).then(
|
||||||
|
function () {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
function (err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
892
resources/assets/js/plugins/ar.json
Normal file
892
resources/assets/js/plugins/ar.json
Normal file
@ -0,0 +1,892 @@
|
|||||||
|
{
|
||||||
|
"navigation": {
|
||||||
|
"dashboard": "الرئيسية",
|
||||||
|
"customers": "العملاء",
|
||||||
|
"items": "الأصناف",
|
||||||
|
"invoices": "الفواتير",
|
||||||
|
"expenses": "النفقات",
|
||||||
|
"estimates": "التقديرات",
|
||||||
|
"payments": "المدفوعات",
|
||||||
|
"reports": "التقارير",
|
||||||
|
"settings": "الإعدادات",
|
||||||
|
"logout": "خروج"
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"view_pdf": "عرض PDF",
|
||||||
|
"download_pdf": "تنزيل PDF",
|
||||||
|
"save": "حفظ",
|
||||||
|
"cancel": "إلغاء الأمر",
|
||||||
|
"update": "تحديث",
|
||||||
|
"download": "تنزيل",
|
||||||
|
"from_date": "من تاريخ",
|
||||||
|
"to_date": "إلى تاريخ",
|
||||||
|
"from": "من",
|
||||||
|
"to": "إلى",
|
||||||
|
"go_back": "إلى الخلف",
|
||||||
|
"back_to_login": "العودة إلى تسجيل الدخول؟",
|
||||||
|
"home": "الرئيسية",
|
||||||
|
"filter": "تصفية",
|
||||||
|
"delete": "حذف",
|
||||||
|
"edit": "تعديل",
|
||||||
|
"view": "عرض",
|
||||||
|
"add_new_item": "إضافة صنف جديد",
|
||||||
|
"clear_all": "مسح الكل",
|
||||||
|
"showing": "عرض",
|
||||||
|
"of": "من",
|
||||||
|
"actions": "العمليات",
|
||||||
|
"subtotal": "المجموع الفرعي",
|
||||||
|
"discount": "خصم",
|
||||||
|
"fixed": "ثابت",
|
||||||
|
"percentage": "نسبة",
|
||||||
|
"tax": "ضريبة",
|
||||||
|
"total_amount": "المبلغ الإجمالي",
|
||||||
|
"bill_to": "مطلوب من",
|
||||||
|
"ship_to": "يشحن إلى",
|
||||||
|
"due": "واجبة السداد",
|
||||||
|
"draft": "مسودة",
|
||||||
|
"sent": "مرسلة",
|
||||||
|
"all": "الكل",
|
||||||
|
"select_all": "تحديد الل",
|
||||||
|
"choose_file": "اضغط هنا لاختيار ملف",
|
||||||
|
"choose_template": "اختيار القالب",
|
||||||
|
"choose": "اختر",
|
||||||
|
"remove": "إزالة",
|
||||||
|
"powered_by": "تصميم",
|
||||||
|
"bytefury": "باترفوري",
|
||||||
|
"select_a_status": "اختر الحالة",
|
||||||
|
"select_a_tax": "اختر الضريبة",
|
||||||
|
"search": "بحث",
|
||||||
|
"are_you_sure": "هل أنت متأكد?",
|
||||||
|
"list_is_empty": "القائمة فارغة.",
|
||||||
|
"no_tax_found": "لا يوجد ضريبة!",
|
||||||
|
"four_zero_four": "404",
|
||||||
|
"you_got_lost": "عفواً! يبدو أنك قد تهت!",
|
||||||
|
"go_home": "عودة إلى الرئيسية",
|
||||||
|
"setting_updated": "تم تحديث الإعدادات بنجاح",
|
||||||
|
"select_state": "اختر الولاية/المنطقة",
|
||||||
|
"select_country": "اختر الدولة",
|
||||||
|
"select_city": "اختر المدينة",
|
||||||
|
"street_1": "عنوان الشارع 1",
|
||||||
|
"street_2": "عنوان الشارع 2",
|
||||||
|
"action_failed": "فشلت العملية",
|
||||||
|
"retry": "أعد المحاولة"
|
||||||
|
},
|
||||||
|
"dashboard": {
|
||||||
|
"select_year": "اختر السنة",
|
||||||
|
"cards": {
|
||||||
|
"due_amount": "المبلغ المطلوب",
|
||||||
|
"customers": "العملاء",
|
||||||
|
"invoices": "الفواتير",
|
||||||
|
"estimates": "التقديرات"
|
||||||
|
},
|
||||||
|
"chart_info": {
|
||||||
|
"total_sales": "المبيعات",
|
||||||
|
"total_receipts": "إجمالي الدخل",
|
||||||
|
"total_expense": "النفقات",
|
||||||
|
"net_income": "صافي الدخل",
|
||||||
|
"year": "اختر السنة"
|
||||||
|
},
|
||||||
|
"weekly_invoices": {
|
||||||
|
"title": "الفواتير الأسبوعية"
|
||||||
|
},
|
||||||
|
"monthly_chart": {
|
||||||
|
"title": "المبيعات والنفقات"
|
||||||
|
},
|
||||||
|
"recent_invoices_card": {
|
||||||
|
"title": "فواتير مستحقة",
|
||||||
|
"due_on": "مستحقة في",
|
||||||
|
"customer": "العميل",
|
||||||
|
"amount_due": "المبلغ المطلوب",
|
||||||
|
"actions": "العمليات",
|
||||||
|
"view_all": "عرض الكل"
|
||||||
|
},
|
||||||
|
"recent_estimate_card": {
|
||||||
|
"title": "أحدث التقديرات",
|
||||||
|
"date": "التاريخ",
|
||||||
|
"customer": "العميل",
|
||||||
|
"amount_due": "المبلغ المطلوب",
|
||||||
|
"actions": "العمليات",
|
||||||
|
"view_all": "عرض الكل"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tax_types": {
|
||||||
|
"name": "الاسم",
|
||||||
|
"description": "الوصف",
|
||||||
|
"percent": "Percent",
|
||||||
|
"compound_tax": "Compound Tax"
|
||||||
|
},
|
||||||
|
"customers": {
|
||||||
|
"title": "العملاء",
|
||||||
|
"add_customer": "إضافة عميل",
|
||||||
|
"contacts_list": "قائمة العملاء",
|
||||||
|
"name": "الاسم",
|
||||||
|
"display_name": "اسم العرض",
|
||||||
|
"primary_contact_name": "اسم التواصل الرئيسي",
|
||||||
|
"contact_name": "اسم تواصل آخر",
|
||||||
|
"amount_due": "المبلغ المطلوب",
|
||||||
|
"email": "البريد الإلكتروني",
|
||||||
|
"address": "العنوان",
|
||||||
|
"phone": "الهاتف",
|
||||||
|
"website": "موقع الإنترنت",
|
||||||
|
"country": "الدولة",
|
||||||
|
"state": "الولاية/المنطقة",
|
||||||
|
"city": "المدينة",
|
||||||
|
"zip_code": "الرمز البريدي",
|
||||||
|
"added_on": "أضيف في",
|
||||||
|
"action": "إجراء",
|
||||||
|
"password": "كلمة المرور",
|
||||||
|
"street_number": "رقم الشارع",
|
||||||
|
"primary_currency": "العملة الرئيسية",
|
||||||
|
"add_new_customer": "إضافة عميل جديد",
|
||||||
|
"save_customer": "حفظ العميل",
|
||||||
|
"update_customer": "تحديث بيانات العميل",
|
||||||
|
"customer": "عميل | عملاء",
|
||||||
|
"new_customer": "عميل جديد",
|
||||||
|
"edit_customer": "تعديل عميل",
|
||||||
|
"basic_info": "معلوات أساسية",
|
||||||
|
"billing_address": "عنوان الفوترة",
|
||||||
|
"shipping_address": "عنوان الشحن",
|
||||||
|
"copy_billing_address": "نسخ من عنوان الفوترة",
|
||||||
|
"no_customers": "لا يوجد عملاء حتى الآن!",
|
||||||
|
"no_customers_found": "لم يتم الحصول على عملاء!",
|
||||||
|
"list_of_customers": "سوف يحتوي هذا القسم على قائمة العملاء.",
|
||||||
|
"primary_display_name": "اسم العرض الرئيسي",
|
||||||
|
"select_currency": "اختر العملة",
|
||||||
|
"select_a_customer": "اختر العميل",
|
||||||
|
"type_or_click": "اكتب أو اضغط للاختيار",
|
||||||
|
|
||||||
|
"confirm_delete": "لن تتمكن من استرداد هذا العميل وجميع الفواتير والتقديرات والمدفوعات ذات الصلة. | لن تتمكن من استرداد هؤلاء العملاء وجميع الفواتير والتقديرات والمدفوعات ذات الصلة.",
|
||||||
|
"created_message": "تم إنشاء العملاء بنجاح",
|
||||||
|
"updated_message": "تم تحديث العملاء بنجاح",
|
||||||
|
"deleted_message": "تم حذف العملاء بنجاح | تم حذف العميل بنجاح"
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"title": "الأصناف",
|
||||||
|
"items_list": "قائمة الأصناف",
|
||||||
|
"name": "الاسم",
|
||||||
|
"unit": "الوحدة",
|
||||||
|
"description": "الوصف",
|
||||||
|
"added_on": "أضيف في",
|
||||||
|
"price": "السعر",
|
||||||
|
"date_of_creation": "تاريخ الإنشاء",
|
||||||
|
"action": "إجراء",
|
||||||
|
"add_item": "إضافة صنف",
|
||||||
|
"save_item": "حفظ الصنف",
|
||||||
|
"update_item": "تحديث الصنف",
|
||||||
|
"item": "صنف | أصناف",
|
||||||
|
"add_new_item": "إضافة صنف جديد",
|
||||||
|
"new_item": "جديد صنف",
|
||||||
|
"edit_item": "تحديث صنف",
|
||||||
|
"no_items": "لا يوجد أصناف حتى الآن!",
|
||||||
|
"list_of_items": "هذا القسم سوف يحتوي على قائمة الأصناف.",
|
||||||
|
"select_a_unit": "اختر الوحدة",
|
||||||
|
|
||||||
|
"item_attached_message": "لا يمكن حذف الصنف قيد الاستخدام",
|
||||||
|
"confirm_delete": "لن تتمكن من استرجاع هذا الصنف | لن تتمكن من استرجاع هذه الأصناف",
|
||||||
|
"created_message": "تم إنشاء الصنف بنجاح",
|
||||||
|
"updated_message": "تم تحديث الصنف بنجاح",
|
||||||
|
"deleted_message": "تم حذف الصنف بنجاح | تم حذف الأصناف بنجاح"
|
||||||
|
},
|
||||||
|
"estimates": {
|
||||||
|
"title": "التقديرات",
|
||||||
|
"estimate": "تقدير | تقديرات",
|
||||||
|
"estimates_list": "قائمة التقديرات",
|
||||||
|
"days": "{days} أيام",
|
||||||
|
"months": "{months} أشهر",
|
||||||
|
"years": "{years} سنوات",
|
||||||
|
"all": "الكل",
|
||||||
|
"paid": "مدفوع",
|
||||||
|
"unpaid": "غير مدفوع",
|
||||||
|
"customer": "العميل",
|
||||||
|
"ref_no": "رقم المرجع.",
|
||||||
|
"number": "الرقم",
|
||||||
|
"amount_due": "المبلغ المطلوب",
|
||||||
|
"partially_paid": "مدفوع جزئيا",
|
||||||
|
"total": "الإجمالي",
|
||||||
|
"discount": "الخصم",
|
||||||
|
"sub_total": "حاصل الجمع",
|
||||||
|
"estimate_number": "رقم تقدير",
|
||||||
|
"ref_number": "رقم المرجع",
|
||||||
|
"contact": "تواصل",
|
||||||
|
"add_item": "إضافة صنف",
|
||||||
|
"date": "تاريخ",
|
||||||
|
"due_date": "تاريخ الاستحقاق",
|
||||||
|
"expiry_date": "تاريخ الصلاحية",
|
||||||
|
"status": "الحالة",
|
||||||
|
"add_tax": "إضافة ضرية",
|
||||||
|
"amount": "المبلغ المطلوب",
|
||||||
|
"action": "إجراء",
|
||||||
|
"notes": "ملاحظات",
|
||||||
|
"tax": "ضريبة",
|
||||||
|
"estimate_template": "قالب",
|
||||||
|
"convert_to_invoice": "تحويل إلى فاتورة",
|
||||||
|
"mark_as_sent": "تحديد كمرسل",
|
||||||
|
"send_estimate": "إرسال التقدير",
|
||||||
|
"record_payment": "تسجيل مدفوات",
|
||||||
|
"add_estimate": "إضافة تقدير",
|
||||||
|
"save_estimate": "حفظ التقدير",
|
||||||
|
"confirm_conversion": "هل تريد تحويل هذا التقدير إلى فاتورة؟",
|
||||||
|
"conversion_message": "تم إنشاء الفاتورة بنجاح",
|
||||||
|
"confirm_send_estimate": "سيتم إرسال هذا التقدير بالبريد الإلكتروني إلى العميل",
|
||||||
|
"confirm_mark_as_sent": "سيتم التحديد كمرسل على هذا التقدير",
|
||||||
|
"confirm_mark_as_accepted": "سيتم التحديد كمقبول على هذا التقدير",
|
||||||
|
"confirm_mark_as_rejected": "سيتم التحديد كمرفوض على هذا التقدير",
|
||||||
|
"no_matching_estimates": "لا يوجد تقديرات مطابقة!",
|
||||||
|
"mark_as_sent_successfully": "تم التحديد كمرسل بنجاح",
|
||||||
|
"send_estimate_successfully": "تم إرسال التقدير بنجاح",
|
||||||
|
"errors": {
|
||||||
|
"required": "حقل مطلوب"
|
||||||
|
},
|
||||||
|
"accepted": "مقبول",
|
||||||
|
"sent": "مرسل",
|
||||||
|
"draft": "مسودة",
|
||||||
|
"declined": "مرفوض",
|
||||||
|
"new_estimate": "تقدير جديد",
|
||||||
|
"add_new_estimate": "إضافة تقدير جديد",
|
||||||
|
"update_Estimate": "تحديث تقدير",
|
||||||
|
"edit_estimate": "تعديل التقدير",
|
||||||
|
"items": "الأصناف",
|
||||||
|
"Estimate": "تقدير | تقديرات",
|
||||||
|
"add_new_tax": "إضافة ضريبة جديدة",
|
||||||
|
"no_estimates": "لا يوجد تقديرات حالياً!",
|
||||||
|
"list_of_estimates": "هذا القسم سوف يحتوي على التقديرات.",
|
||||||
|
"mark_as_rejected": "تحديد كمرفوض",
|
||||||
|
"mark_as_accepted": "تحديد كمقروء",
|
||||||
|
|
||||||
|
"marked_as_accepted_message": "تحديد التقدير كمقبول",
|
||||||
|
"marked_as_rejected_message": "تحديد التقدير كمرفوض",
|
||||||
|
"confirm_delete": "لن تستطيع استرجاع هذا التقدير | لن تستطيع إستعادة هذه التقديرات",
|
||||||
|
"created_message": "تم إنشاء التقدير بنجاح",
|
||||||
|
"updated_message": "تم تحديث التقدير بنجاح",
|
||||||
|
"deleted_message": "تم حذف التقدير بنجاح | تم حذف التقديرات بنجاح",
|
||||||
|
"user_email_does_not_exist": "البريد الالكتروني للمستخدم غير موجود",
|
||||||
|
"something_went_wrong": "خطأ غير معروف!",
|
||||||
|
"item": {
|
||||||
|
"title": "اسم الصنف",
|
||||||
|
"description": "الوصف",
|
||||||
|
"quantity": "الكمية",
|
||||||
|
"price": "السعر",
|
||||||
|
"discount": "الخصم",
|
||||||
|
"total": "الإجمالي",
|
||||||
|
"total_discount": "مجموع الخصم",
|
||||||
|
"sub_total": "حاصل الجمع",
|
||||||
|
"tax": "الضرية",
|
||||||
|
"amount": "المبلغ المطلوب",
|
||||||
|
"select_an_item": "اكتب أو اختر الصنف",
|
||||||
|
"type_item_description": "اكتب وصف الصنف (اختياري)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"invoices": {
|
||||||
|
"title": "الفواتير",
|
||||||
|
"invoices_list": "قائمة الفواتير",
|
||||||
|
"days": "{days} أيام",
|
||||||
|
"months": "{months} أشهر",
|
||||||
|
"years": "{years} سنوات",
|
||||||
|
"all": "الكل",
|
||||||
|
"paid": "مدفوع",
|
||||||
|
"unpaid": "غير مدفوع",
|
||||||
|
"customer": "العميل",
|
||||||
|
"paid_status": "حالة الدفع",
|
||||||
|
"ref_no": "رقم المرجع.",
|
||||||
|
"number": "الرقم",
|
||||||
|
"amount_due": "المبلغ المطلوب",
|
||||||
|
"partially_paid": "مدفوع جزئياً",
|
||||||
|
"total": "الإجمالي",
|
||||||
|
"discount": "الخصم",
|
||||||
|
"sub_total": "حاصل الجمع",
|
||||||
|
"invoice": "فاتورة | فواتير",
|
||||||
|
"invoice_number": "رقم الفاتورة",
|
||||||
|
"ref_number": "رقم المرجع",
|
||||||
|
"contact": "تواصل",
|
||||||
|
"add_item": "إضافة صنف",
|
||||||
|
"date": "التاريخ",
|
||||||
|
"due_date": "تاريخ الاستحقاق",
|
||||||
|
"status": "الحالة",
|
||||||
|
"add_tax": "إضافة ضريبة",
|
||||||
|
"amount": "المبلغ المطلوب",
|
||||||
|
"action": "إجراء",
|
||||||
|
"notes": "ملاحظات",
|
||||||
|
"view": "عرض",
|
||||||
|
"send_invoice": "إرسال الفاتورة",
|
||||||
|
"invoice_template": "قالب الفاتورة",
|
||||||
|
"template": "قالب",
|
||||||
|
"mark_as_sent": "تحديد كمرسل",
|
||||||
|
"confirm_send_invoice": "سيتم إرسال هذه الفاتورة بالبريد الألكتروني إلى العميل",
|
||||||
|
"invoice_mark_as_sent": "سيتم تحديد هذه الفاتورة كمرسلة",
|
||||||
|
"confirm_send": "سيتم إرسال هذه الفاتورة بالبريد الألكتروني إلى العميل",
|
||||||
|
"invoice_date": "تاريخ الفاتورة",
|
||||||
|
"record_payment": "تسجيل مدفوعات",
|
||||||
|
"add_new_invoice": "إضافة فاتورة جديدة",
|
||||||
|
"update_expense": "تحديث المصروفات",
|
||||||
|
"edit_invoice": "تعديل الفاتورة",
|
||||||
|
"new_invoice": "فاتورة جديدة",
|
||||||
|
"save_invoice": "حفظ الفاتورة",
|
||||||
|
"update_invoice": "تحديث الفاتورة",
|
||||||
|
"add_new_tax": "إضافة ضريبة جديدة",
|
||||||
|
"no_invoices": "لا يوجد فواتير حتى الآن!",
|
||||||
|
"list_of_invoices": "قائمة الفواتير .",
|
||||||
|
"select_invoice": "اختر الفاتورة",
|
||||||
|
"no_matching_invoices": "لا يوجد فواتير مطابقة!",
|
||||||
|
"mark_as_sent_successfully": "تم تحديد الفاتورة كمرسلة بنجاح",
|
||||||
|
"send_invoice_successfully": "تم إرسال الفاتورة بنجاح",
|
||||||
|
"item": {
|
||||||
|
"title": "اسم الصنف",
|
||||||
|
"description": "الوصف",
|
||||||
|
"quantity": "الكمية",
|
||||||
|
"price": "السعر",
|
||||||
|
"discount": "الخصم",
|
||||||
|
"total": "الإجمالي",
|
||||||
|
"total_discount": "إجمالي الخصم",
|
||||||
|
"sub_total": "حاصل الجمع",
|
||||||
|
"tax": "الضريبة",
|
||||||
|
"amount": "المبلغ المطلوب",
|
||||||
|
"select_an_item": "اكتب أو انقر لاختيار صنف",
|
||||||
|
"type_item_description": "وصف الصنف (اختياري)"
|
||||||
|
},
|
||||||
|
|
||||||
|
"payment_attached_message": "هناك مدفوعات مرتبطة بالفعل بإحدى الفواتير المحددة. تأكد من حذف المدفوعات المرتبطة أولاً قبل حذف الفاتورة.",
|
||||||
|
"confirm_delete": "لن تتمكن من استرجاع الفاتورة بعد هذه الإجراء | لن تتمكن من استرجاع الفواتير بعد هذا الإجراء",
|
||||||
|
"created_message": "تم إنشاء الفاتورة بنجاح",
|
||||||
|
"updated_message": "تم تحديث الفاتورة بنجاح",
|
||||||
|
"deleted_message": "تم حذف الفاتورة بنجاح | تم حذف الفواتير بنجاح",
|
||||||
|
"marked_as_sent_message": "تم إرسال الفاتورة بنجاح",
|
||||||
|
"user_email_does_not_exist": "البريد الإلكتروني للمستخدم غير موجود!",
|
||||||
|
"something_went_wrong": "خطأ غير معروف!",
|
||||||
|
"invalid_due_amount_message": "المبلغ النهائي للفاتورة لا يمكن أن يكون أقل من المبلغ المطلوب لها. رجاءاً حدث الفاتورة أو قم بحذف المدفوعات المرتبطة بها للاستمرار."
|
||||||
|
},
|
||||||
|
"credit_notes": {
|
||||||
|
"title": "ملاحظات إئتمانية",
|
||||||
|
"credit_notes_list": "قائمة الملاحظات الإئتمانية",
|
||||||
|
"credit_notes": "ملاحظات إئتمانية",
|
||||||
|
"contact": "تواصل",
|
||||||
|
"date": "التاريخ",
|
||||||
|
"amount": "المبلغ المطلوب",
|
||||||
|
"action": "إجراء",
|
||||||
|
"credit_number": "الرقم الإئتماني",
|
||||||
|
"notes": "ملاحظات",
|
||||||
|
"confirm_delete": "هل تريد حفذف هذه الملاحظة الإئتمانية؟",
|
||||||
|
"item": {
|
||||||
|
"title": "اسم الصنف",
|
||||||
|
"description": "الوصف",
|
||||||
|
"quantity": "الكمية",
|
||||||
|
"price": "السعر",
|
||||||
|
"discount": "الخصم",
|
||||||
|
"total": "الإجمالي",
|
||||||
|
"total_discount": "إجمالي الخصم",
|
||||||
|
"sub_total": "حاصل الجمع",
|
||||||
|
"tax": "الضريبة"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"payments": {
|
||||||
|
"title": "المدفوعات",
|
||||||
|
"payments_list": "قائمة المدفوعات",
|
||||||
|
"record_payment": "تسجيل دفعة",
|
||||||
|
"customer": "العميل",
|
||||||
|
"date": "التاريخ",
|
||||||
|
"amount": "المبلغ المطلوب",
|
||||||
|
"action": "إجراء",
|
||||||
|
"payment_number": "رقم الدفعة",
|
||||||
|
"payment_mode": "نوع الدفعة",
|
||||||
|
"invoice": "الفاتورة",
|
||||||
|
"note": "ملاحظة",
|
||||||
|
"add_payment": "إضافة دفعة",
|
||||||
|
"new_payment": "دفعة جديدة",
|
||||||
|
"edit_payment": "تعديل الدفعة",
|
||||||
|
"view_payment": "عرض الدفعة",
|
||||||
|
"add_new_payment": "إضافة دفعة جديدة",
|
||||||
|
"save_payment": "حفظ الدفعة",
|
||||||
|
"update_payment": "تحديث الدفعة",
|
||||||
|
"payment": "دفعة | مدفوعات",
|
||||||
|
"no_payments": "لا يوجد مدفوعات حتى الآن!",
|
||||||
|
"no_matching_payments": "لا توجد مدفوعات مطابقة!",
|
||||||
|
"list_of_payments": "سوف تحتوي هذه القائمة على مدفوعات الفواتير.",
|
||||||
|
"select_payment_mode": "اختر طريقة الدفع",
|
||||||
|
|
||||||
|
"confirm_delete": "لن تكون قادر على استرجاع هذه الدفعة | لن تكون قادراً على استرجاع هذه المدفوعات",
|
||||||
|
"created_message": "تم إنشاء الدفعة بنجاح",
|
||||||
|
"updated_message": "تم تحديث الدفعة بنجاح",
|
||||||
|
"deleted_message": "تم حذف الدفعة بنجاح | تم حذف المدفوعات بنجاح",
|
||||||
|
"invalid_amount_message": "قيمة الدفعة غير صحيحة!"
|
||||||
|
},
|
||||||
|
"expenses": {
|
||||||
|
"title": "النفقات",
|
||||||
|
"expenses_list": "قائمة النفقات",
|
||||||
|
"expense_title": "Title",
|
||||||
|
"select_a_customer": "حدد عميلاً",
|
||||||
|
"customer": "العميل",
|
||||||
|
"contact": "تواصل",
|
||||||
|
"category": "الفئة",
|
||||||
|
"from_date": "من تاريخ",
|
||||||
|
"to_date": "حتى تاريخ",
|
||||||
|
"expense_date": "التاريخ",
|
||||||
|
"description": "الوصف",
|
||||||
|
"receipt": "سند القبض",
|
||||||
|
"amount": "المبلغ المطلوب",
|
||||||
|
"action": "إجراء",
|
||||||
|
"note": "ملاحظة",
|
||||||
|
"category_id": "رمز الفئة",
|
||||||
|
"date": "تاريخ النفقات",
|
||||||
|
"add_expense": "أضف نفقات",
|
||||||
|
"add_new_expense": "أضف نفقات جديدة",
|
||||||
|
"save_expense": "حفظ النفقات",
|
||||||
|
"update_expense": "تحديث النفقات",
|
||||||
|
"download_receipt": "تنزيل السند",
|
||||||
|
"edit_expense": "تعديل النفقات",
|
||||||
|
"new_expense": "نفقات جديدة",
|
||||||
|
"expense": "إنفاق | نفقات",
|
||||||
|
"no_expenses": "لا يوجد نفقات حتى الآن!",
|
||||||
|
"list_of_expenses": "هذه القائمة ستحتوي النفقات الخاصة بك",
|
||||||
|
|
||||||
|
"confirm_delete": "لن تتمكن من استرجاع هذا الإنفاق | لن تتمكن من استرجاع هذه النفقات",
|
||||||
|
"created_message": "تم إنشاء النفقات بنجاح",
|
||||||
|
"updated_message": "تم تحديث النفقات بنجاح",
|
||||||
|
"deleted_message": "تم حذف النفقات بنجاح",
|
||||||
|
"categories": {
|
||||||
|
"categories_list": "قائمة الفئات",
|
||||||
|
"title": "العنوان",
|
||||||
|
"name": "الاسم",
|
||||||
|
"description": "الوصف",
|
||||||
|
"amount": "المبلغ المطلوب",
|
||||||
|
"actions": "العمليات",
|
||||||
|
"add_category": "إضافة فئمة",
|
||||||
|
"new_category": "فئة جديدة",
|
||||||
|
"category": "فئة | فئات",
|
||||||
|
"select_a_category": "اختر الفئة"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"login": {
|
||||||
|
"email": "البريد الإلكتروني",
|
||||||
|
"password": "كلمة المرور",
|
||||||
|
"forgot_password": "نسيت كلمة المرور؟",
|
||||||
|
"or_signIn_with": "أو سجل الدخول بواسطة",
|
||||||
|
"login": "دخول",
|
||||||
|
"register": "تسجيل",
|
||||||
|
"reset_password": "إعادة تعيين كلمة المرور",
|
||||||
|
"password_reset_successfully": "تم إعادة تعيين كلمة المرور بنجاح",
|
||||||
|
"enter_email": "أدخل البريد الالكتروني",
|
||||||
|
"enter_password": "أكتب كلمة المرور",
|
||||||
|
"retype_password": "أعد كتابة كلمة المرور",
|
||||||
|
"login_placeholder": "mail@example.com"
|
||||||
|
},
|
||||||
|
"reports": {
|
||||||
|
"title": "تقرير",
|
||||||
|
"from_date": "من تاريخ",
|
||||||
|
"to_date": "حتى تاريخ",
|
||||||
|
"status": "الحالة",
|
||||||
|
"paid": "مدفوع",
|
||||||
|
"unpaid": "غير مدفوع",
|
||||||
|
"download_pdf": "تنزيل PDF",
|
||||||
|
"view_pdf": "عرض PDF",
|
||||||
|
"update_report": "تحديث التقرير",
|
||||||
|
"report": "تقرير | تقارير",
|
||||||
|
"profit_loss": {
|
||||||
|
"profit_loss": "الخسائر والأرباح",
|
||||||
|
"to_date": "حتى تاريخ",
|
||||||
|
"from_date": "من تاريخ",
|
||||||
|
"date_range": "اختر مدى التاريخ"
|
||||||
|
},
|
||||||
|
"sales": {
|
||||||
|
"sales": "المبيعات",
|
||||||
|
"date_range": "اختر مدى التاريخ",
|
||||||
|
"to_date": "حتى تاريخ",
|
||||||
|
"from_date": "من تاريخ",
|
||||||
|
"report_type": "نوع التقرير"
|
||||||
|
},
|
||||||
|
"taxes": {
|
||||||
|
"taxes": "الضرائب",
|
||||||
|
"to_date": "حتى تاريخ",
|
||||||
|
"from_date": "من تاريخ",
|
||||||
|
"date_range": "اختر مدى التاريخ"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"required": "حقل مطلوب"
|
||||||
|
},
|
||||||
|
"invoices": {
|
||||||
|
"invoice": "الفاتورة",
|
||||||
|
"invoice_date": "تاريخ الفاتورة",
|
||||||
|
"due_date": "تاريخ الاستحقاق",
|
||||||
|
"amount": "المبلغ المطلوب",
|
||||||
|
"contact_name": "اسم التواصل",
|
||||||
|
"status": "الحالة"
|
||||||
|
},
|
||||||
|
"estimates": {
|
||||||
|
"estimate": "تقدير",
|
||||||
|
"estimate_date": "تاريخ التقدير",
|
||||||
|
"due_date": "مستحق بتاريخ",
|
||||||
|
"estimate_number": "رقم مستحق",
|
||||||
|
"ref_number": "رقم المرجع",
|
||||||
|
"amount": "المبلغ المطلوب",
|
||||||
|
"contact_name": "اسم التواصل",
|
||||||
|
"status": "الحالة"
|
||||||
|
},
|
||||||
|
"expenses": {
|
||||||
|
"expenses": "النفقات",
|
||||||
|
"category": "الفئة",
|
||||||
|
"date": "التاريخ",
|
||||||
|
"amount": "المبلغ المطلوب",
|
||||||
|
"to_date": "حتى تاريخ",
|
||||||
|
"from_date": "من تاريخ",
|
||||||
|
"date_range": "اختر مدى التاريخ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"menu_title": {
|
||||||
|
"account_settings": "إعدادات الحساب",
|
||||||
|
"company_information": "معلومات المنشأة",
|
||||||
|
"customization": "تخصيص",
|
||||||
|
"preferences": "تفضيلات",
|
||||||
|
"notifications": "تنبيهات",
|
||||||
|
"tax_types": "نوع الضريبة",
|
||||||
|
"expense_category": "فئات النفقات",
|
||||||
|
"update_app": "تحديث النظام"
|
||||||
|
},
|
||||||
|
"title": "إعدادات",
|
||||||
|
"setting": "إعدادات | إعدادات",
|
||||||
|
"general": "عام",
|
||||||
|
"language": "اللغة",
|
||||||
|
"primary_currency": "العملة الرئيسية",
|
||||||
|
"timezone": "المنطقة الزمنية",
|
||||||
|
"date_format": "صيغة التاريخ",
|
||||||
|
"currencies": {
|
||||||
|
"title": "العملات",
|
||||||
|
"currency": "العملة | العملات",
|
||||||
|
"currencies_list": "قائمة العملات",
|
||||||
|
"select_currency": "اختر العملة",
|
||||||
|
"name": "الاسم",
|
||||||
|
"code": "المرجع",
|
||||||
|
"symbol": "الرمز",
|
||||||
|
"precision": "الدقة",
|
||||||
|
"thousand_separator": "فاصل الآلاف",
|
||||||
|
"decimal_separator": "الفاصلة العشرية",
|
||||||
|
"position": "الموقع",
|
||||||
|
"position_of_symbol": "موقع رمز العملة",
|
||||||
|
"right": "يمين",
|
||||||
|
"left": "يسار",
|
||||||
|
"action": "إجراء",
|
||||||
|
"add_currency": "أضف عملة"
|
||||||
|
},
|
||||||
|
"mail": {
|
||||||
|
"host": "خادم البريد",
|
||||||
|
"port": "منفذ البريد",
|
||||||
|
"driver": "مشغل البريد",
|
||||||
|
"secret": "سري",
|
||||||
|
"mailgun_secret": "الرمز السري لـ Mailgun",
|
||||||
|
"mailgun_domain": "المجال",
|
||||||
|
"mailgun_endpoint": "النهاية الطرفية لـ Mailgun",
|
||||||
|
"ses_secret": "SES الرمز السري",
|
||||||
|
"ses_key": "SES مفتاح",
|
||||||
|
"password": "كلمة مرور البريد الالكتروني",
|
||||||
|
"username": "اسم المستخدم للبريد الإلكتروني",
|
||||||
|
"mail_config": "إعدادات البريد الالكتروني",
|
||||||
|
"from_name": "اسم المرسل",
|
||||||
|
"from_mail": "عنوان البريد الالكتروني للمرسل",
|
||||||
|
"encryption": "صيغة ا لتشفير",
|
||||||
|
"mail_config_desc": "أدناه هو نموذج لتكوين برنامج تشغيل البريد الإلكتروني لإرسال رسائل البريد الإلكتروني من التطبيق. يمكنك أيضًا تهيئة موفري الجهات الخارجية مثل Sendgrid و SES إلخ."
|
||||||
|
},
|
||||||
|
"pdf": {
|
||||||
|
"title": "PDF إعدادات",
|
||||||
|
"footer_text": "نص التذييل",
|
||||||
|
"pdf_layout": "اتجاه صفحة PDF"
|
||||||
|
},
|
||||||
|
"company_info": {
|
||||||
|
"company_info": "معلومات الشركة",
|
||||||
|
"company_name": "اسم الشركة",
|
||||||
|
"company_logo": "شعار الشركة",
|
||||||
|
"section_description": "معلومات عن شركتك سيتم عرضها على الفواتير والتقديرات والمستندات الأخرى.",
|
||||||
|
"phone": "الهاتف",
|
||||||
|
"country": "الدولة",
|
||||||
|
"state": "الولاية/المنطقة",
|
||||||
|
"city": "المدينة",
|
||||||
|
"address": "العنوان",
|
||||||
|
"zip": "الرمز البريدي",
|
||||||
|
"save": "حفظ",
|
||||||
|
"updated_message": "تم تحديث معلومات الشركة بنجاح"
|
||||||
|
},
|
||||||
|
"customization": {
|
||||||
|
"customization": "التخصيص",
|
||||||
|
"save": "حفظ",
|
||||||
|
"addresses": {
|
||||||
|
"title": "العنوان",
|
||||||
|
"section_description": "يمكنك ضبط عنوان إرسال فواتير العملاء وتنسيق عنوان شحن العملاء (معروض في PDF فقط).",
|
||||||
|
"customer_billing_address": "عنوان فواتير العميل",
|
||||||
|
"customer_shipping_address": "عنوان الشحن للعميل",
|
||||||
|
"company_address": "عنوان الشركة",
|
||||||
|
"insert_fields": "أضف حقل",
|
||||||
|
"contact": "تواصل",
|
||||||
|
"address": "العنوان",
|
||||||
|
"display_name": "الاسم الظاهر",
|
||||||
|
"primary_contact_name": "مسؤول التواصل الرئيسي",
|
||||||
|
"email": "البريد الإلكتروني",
|
||||||
|
"website": "موقع الإنترنت",
|
||||||
|
"name": "الاسم",
|
||||||
|
"country": "الدولة",
|
||||||
|
"state": "الولاية/المنطقة",
|
||||||
|
"city": "المدينة",
|
||||||
|
"company_name": "اسم الشركة",
|
||||||
|
"address_street_1": "عنوان الشارع 1",
|
||||||
|
"address_street_2": "عنوان الشارع 2",
|
||||||
|
"phone": "الهاتف",
|
||||||
|
"zip_code": "الرمز البريدي",
|
||||||
|
"address_setting_updated": "تم تحديث العنوان بنجاح"
|
||||||
|
},
|
||||||
|
"updated_message": "تم تحديث معلومات الشركة بنجاح",
|
||||||
|
|
||||||
|
"invoices": {
|
||||||
|
"title": "الفواتير",
|
||||||
|
"notes": "ملاحظات",
|
||||||
|
"invoice_prefix": "بادئة رقم الفاتورة",
|
||||||
|
"invoice_settings": "إعدادات الفاتورة",
|
||||||
|
"autogenerate_invoice_number": "ترقيم آلي للفاتورة",
|
||||||
|
"invoice_setting_description": "تعطيل الترقيم الآلي ، إذا كنت لا ترغب في إنشاء أرقام الفاتورة تلقائيًا في كل مرة تقوم فيها بإنشاء فاتورة جديدة.",
|
||||||
|
"enter_invoice_prefix": "أدخل بادئة رقم الفاتورة",
|
||||||
|
"terms_and_conditions": "الأحكام والشروط",
|
||||||
|
"invoice_setting_updated": "تم تحديث إعداد الفاتورة بنجاح"
|
||||||
|
},
|
||||||
|
|
||||||
|
"estimates": {
|
||||||
|
"title": "التقديرات",
|
||||||
|
"estimate_prefix": "بادئة رقم التقدير",
|
||||||
|
"estimate_settings": "إعدادت التقدير",
|
||||||
|
"autogenerate_estimate_number": "ترقيم آلي للتقدير",
|
||||||
|
"estimate_setting_description": "تعطيل الترقيم الآلي ، إذا كنت لا ترغب في إنشاء أرقام التقديرات تلقائيًا في كل مرة تقوم فيها بإنشاء تقدير جديد.",
|
||||||
|
"enter_estimate_prefix": "أدخل بادئة رقم التقدير",
|
||||||
|
"estimate_setting_updated": "تم تحديث إعدادات التقدير بنجاح"
|
||||||
|
},
|
||||||
|
|
||||||
|
"payments": {
|
||||||
|
"title": "المدفوعات",
|
||||||
|
"payment_prefix": "بادئة رقم الدفعة",
|
||||||
|
"payment_settings": "إعدادات الدفعة",
|
||||||
|
"autogenerate_payment_number": "ترقيم آلي للمدفوعات",
|
||||||
|
"payment_setting_description": "تعطيل الترقيم الآلي ، إذا كنت لا ترغب في إنشاء أرقام الدفعة تلقائيًا في كل مرة تقوم فيها بإنشاء دفعة جديدة.",
|
||||||
|
"enter_payment_prefix": "أدخل بادئة رقم الدفعة",
|
||||||
|
"payment_setting_updated": "تم تحديث إعدادات الدفعة بنجاح"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"account_settings": {
|
||||||
|
"profile_picture": "صورة الملف الشخصي",
|
||||||
|
"name": "الاسم",
|
||||||
|
"email": "البريد الإلكتروني",
|
||||||
|
"password": "كلمة المرور",
|
||||||
|
"confirm_password": "أعد كتابة كلمة المرور",
|
||||||
|
"account_settings": "إعدادات الجساب",
|
||||||
|
"save": "حفظ",
|
||||||
|
"section_description": "يمكنك تحديث اسمك والبريد الإلكتروني وكلمة المرور باستخدام النموذج أدناه.",
|
||||||
|
"updated_message": "تم تحديث إعدادات الحساب بنجاح"
|
||||||
|
},
|
||||||
|
"user_profile": {
|
||||||
|
"name": "الاسم",
|
||||||
|
"email": "البريد الإلكتروني",
|
||||||
|
"password": "كلمة المرور",
|
||||||
|
"confirm_password": "أعد كتابة كلمة المرور"
|
||||||
|
},
|
||||||
|
"notification": {
|
||||||
|
"title": "الإشعارات",
|
||||||
|
"email": "إرسال الإشعارات إلى",
|
||||||
|
"description": "ما هي إشعارات البريد الإلكتروني التي ترغب في تلقيها عندما يتغير شيء ما؟",
|
||||||
|
"invoice_viewed": "تم عرض الفاتورة",
|
||||||
|
"invoice_viewed_desc": "عندما يستعرض عميلك الفاتورة المرسلة عبر الشاشة الرئيسية.",
|
||||||
|
"estimate_viewed": "تم عرض التقدير",
|
||||||
|
"estimate_viewed_desc": "عندما يستعرض عميلك التقدير المرسلة عبر الشاشة الرئيسية.",
|
||||||
|
"save": "حفظ",
|
||||||
|
"email_save_message": "تم حفظ البريد الإلكتروني بنجاح",
|
||||||
|
"please_enter_email": "فضلاً أدخل البريد الإلكتروني"
|
||||||
|
},
|
||||||
|
"tax_types": {
|
||||||
|
"title": "أنواع الضرائب",
|
||||||
|
"add_tax": "أضف ضريبة",
|
||||||
|
"description": "يمكنك إضافة أو إزالة الضرائب كما يحلو لك. النظام يدعم الضرائب على العناصر الفردية وكذلك على الفاتورة.",
|
||||||
|
"add_new_tax": "إضافة ضريبة جديدة",
|
||||||
|
"tax_settings": "إعدادات الضريبة",
|
||||||
|
"tax_per_item": "ضريبة على الصنف",
|
||||||
|
"tax_name": "اسم الضريبة",
|
||||||
|
"compound_tax": "ضريبة مجمعة",
|
||||||
|
"percent": "نسبة مؤوية",
|
||||||
|
"action": "إجراء",
|
||||||
|
"tax_setting_description": "قم بتمكين هذا إذا كنت تريد إضافة ضرائب لعناصر الفاتورة الفردية. بشكل افتراضي ، تضاف الضرائب مباشرة إلى الفاتورة.",
|
||||||
|
"created_message": "تم إنشاء نوع الضريبة بنجاح",
|
||||||
|
"updated_message": "تم تحديث نوع الضريبة بنجاح",
|
||||||
|
"deleted_message": "تم حذف نوع الضريبة بنجاح",
|
||||||
|
"confirm_delete": "لن تتمكن من استرجاع نوع الضرية هذا",
|
||||||
|
"already_in_use": "ضريبة قيد الاستخدام"
|
||||||
|
},
|
||||||
|
"expense_category": {
|
||||||
|
"title": "فئات النفقات",
|
||||||
|
"action": "إجراء",
|
||||||
|
"description": "الفئات مطلوبة لإضافة إدخالات النفقات. يمكنك إضافة أو إزالة هذه الفئات وفقًا لتفضيلاتك.",
|
||||||
|
"add_new_category": "إضافة فئة جديدة",
|
||||||
|
"category_name": "اسم الفئة",
|
||||||
|
"category_description": "الوصف",
|
||||||
|
"created_message": "تم إنشاء نوع النفقات بنجاح",
|
||||||
|
"deleted_message": "تم حذف نوع النفقات بنجاح",
|
||||||
|
"updated_message": "تم تحديث نوع النفقات بنجاح",
|
||||||
|
"confirm_delete": "لن تتمكن من استرجاع نوع النفقات هذا",
|
||||||
|
"already_in_use": "نوع قيد الاستخدام"
|
||||||
|
},
|
||||||
|
"preferences": {
|
||||||
|
"currency": "العملة",
|
||||||
|
"language": "اللغة",
|
||||||
|
"time_zone": "المنطة الزمنية",
|
||||||
|
"fiscal_year": "السنة المالية",
|
||||||
|
"date_format": "صيغة التاريخ",
|
||||||
|
"discount_setting": "إعدادات الخصم",
|
||||||
|
"discount_per_item": "خصم على الصنف ",
|
||||||
|
"discount_setting_description": "قم بتمكين هذا إذا كنت تريد إضافة خصم إلى عناصر الفاتورة الفردية. بشكل افتراضي ، يتم إضافة الخصم مباشرة إلى الفاتورة.",
|
||||||
|
"save": "حفظ",
|
||||||
|
"preference": "تفضيل | تفضيلات",
|
||||||
|
"general_settings": "التفضيلات الافتراضية للنظام.",
|
||||||
|
"updated_message": "تم تحديث التفضيلات بنجاح",
|
||||||
|
"select_language": "اختر اللغة",
|
||||||
|
"select_time_zone": "اختر المنطة الزمنية",
|
||||||
|
"select_date_formate": "اختر صيغة التاريخ",
|
||||||
|
"select_financial_year": "اختر السنة المالية"
|
||||||
|
},
|
||||||
|
"update_app": {
|
||||||
|
"title": "تحديث النظام",
|
||||||
|
"description": "يمكنك تحديث النظام بسهولة عن طريق البحث عن تحديث جديد بالنقر فوق الزر أدناه",
|
||||||
|
"check_update": "تحقق من التحديثات",
|
||||||
|
"avail_update": "تحديث جديد متوفر",
|
||||||
|
"next_version": "النسخة الجديدة",
|
||||||
|
"update": "حدث الآن",
|
||||||
|
"update_progress": "قيد التحديث...",
|
||||||
|
"progress_text": "سوف يستغرق التحديث بضع دقائق. يرجى عدم تحديث الشاشة أو إغلاق النافذة قبل انتهاء التحديث",
|
||||||
|
"update_success": "تم تحديث النظام! يرجى الانتظار حتى يتم إعادة تحميل نافذة المتصفح تلقائيًا.",
|
||||||
|
"latest_message": "لا يوجد تحديثات متوفرة! لديك حالياً أحدث نسخة.",
|
||||||
|
"current_version": "النسخة الحالية",
|
||||||
|
"download_zip_file": "تنزيل ملف ZIP",
|
||||||
|
"unzipping_package": "حزمة فك الضغط",
|
||||||
|
"copying_files": "نسخ الملفات",
|
||||||
|
"running_migrations": "إدارة عمليات الترحيل",
|
||||||
|
"finishing_update": "تحديث التشطيب",
|
||||||
|
"update_failed": "فشل التحديث",
|
||||||
|
"update_failed_text": "آسف! فشل التحديث الخاص بك في: {step} خطوة"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wizard": {
|
||||||
|
"account_info": "معلومات الحساب",
|
||||||
|
"account_info_desc": "سيتم استخدام التفاصيل أدناه لإنشاء حساب المسؤول الرئيسي. كما يمكنك تغيير التفاصيل في أي وقت بعد تسجيل الدخول.",
|
||||||
|
"name": "الاسم",
|
||||||
|
"email": "البريد الإلكتروني",
|
||||||
|
"password": "كلمة المرور",
|
||||||
|
"confirm_password": "أعد كتابة كلمة المرور",
|
||||||
|
"save_cont": "حفظ واستمرار",
|
||||||
|
"company_info": "معلومات الشركة",
|
||||||
|
"company_info_desc": "سيتم عرض هذه المعلومات على الفواتير. لاحظ أنه يمكنك تعديل هذا لاحقًا في صفحة الإعدادات.",
|
||||||
|
"company_name": "اسم الشركة",
|
||||||
|
"company_logo": "شعار الشركة",
|
||||||
|
"logo_preview": "استعراض الشعار",
|
||||||
|
"preferences": "التفضيلات",
|
||||||
|
"preferences_desc": "التفضيلات الافتراضية للنظام",
|
||||||
|
"country": "الدولة",
|
||||||
|
"state": "الولاية/المنطقة",
|
||||||
|
"city": "المدينة",
|
||||||
|
"address": "العنوان",
|
||||||
|
"street": "العنوان 1 | العنوان 2",
|
||||||
|
"phone": "الهاتف",
|
||||||
|
"zip_code": "الرمز البريدي",
|
||||||
|
"go_back": "للخلف",
|
||||||
|
"currency": "العملة",
|
||||||
|
"language": "اللغة",
|
||||||
|
"time_zone": "المنطة الزمنية",
|
||||||
|
"fiscal_year": "السنة المالية",
|
||||||
|
"date_format": "صيغة التاريخ",
|
||||||
|
"from_address": "من العنوان",
|
||||||
|
"username": "اسم المستخدم",
|
||||||
|
"next": "التالي",
|
||||||
|
"continue": "استمرار",
|
||||||
|
"skip": "تخطي",
|
||||||
|
"database": {
|
||||||
|
"database": "عنوان قاعدة البيانات",
|
||||||
|
"connection": "اتصال قاعدة البيانات",
|
||||||
|
"host": "خادم قاعدة البيانات",
|
||||||
|
"port": "منفذ قاعدة البيانات",
|
||||||
|
"password": "كلمة مرور قاعدة البيانات",
|
||||||
|
"app_url": "عنوان الإنترنت للنظام",
|
||||||
|
"username": "اسم المستخدم لقاعدة البيانات",
|
||||||
|
"db_name": "سم قاعدة البيانات",
|
||||||
|
"desc": "قم بإنشاء قاعدة بيانات على الخادم الخاص بك وتعيين بيانات الاعتماد باستخدام النموذج أدناه."
|
||||||
|
},
|
||||||
|
"permissions": {
|
||||||
|
"permissions": "الأذونات",
|
||||||
|
"permission_confirm_title": "هل أنت متأكد من الاستمرار؟",
|
||||||
|
"permission_confirm_desc": "فشل فحص أذونات المجلد",
|
||||||
|
"permission_desc": "فيما يلي قائمة أذونات المجلد المطلوبة حتى يعمل التطبيق. في حالة فشل فحص الإذن ، تأكد من تحديث أذونات المجلد."
|
||||||
|
},
|
||||||
|
"mail": {
|
||||||
|
"host": "خادم البريد",
|
||||||
|
"port": "منفذ البريد",
|
||||||
|
"driver": "مشغل البريد",
|
||||||
|
"secret": "سري",
|
||||||
|
"mailgun_secret": "الرمز السري لـ Mailgun",
|
||||||
|
"mailgun_domain": "المجال",
|
||||||
|
"mailgun_endpoint": "النهاية الطرفية لـ Mailgun",
|
||||||
|
"ses_secret": "SES الرمز السري",
|
||||||
|
"ses_key": "SES مفتاح",
|
||||||
|
"password": "كلمة مرور البريد الالكتروني",
|
||||||
|
"username": "اسم المستخدم للبريد الإلكتروني",
|
||||||
|
"mail_config": "إعدادات البريد الالكتروني",
|
||||||
|
"from_name": "اسم المرسل",
|
||||||
|
"from_mail": "عنوان البريد الالكتروني للمرسل",
|
||||||
|
"encryption": "صيغة ا لتشفير",
|
||||||
|
"mail_config_desc": "أدناه هو نموذج لتكوين برنامج تشغيل البريد الإلكتروني لإرسال رسائل البريد الإلكتروني من التطبيق. يمكنك أيضًا تهيئة موفري الجهات الخارجية مثل Sendgrid و SES إلخ."
|
||||||
|
},
|
||||||
|
"req": {
|
||||||
|
"system_req": "متطلبات النظام",
|
||||||
|
"php_req_version": "Php (النسخة المطلوبة {version} بحد أدنى)",
|
||||||
|
"check_req": "فحص متطلبات النظام",
|
||||||
|
"system_req_desc": "يحتوي النظام على بعض متطلبات الخادم. تأكد من أن خادمك لديه نسخة php المطلوبة وجميع الامتدادات المذكورة أدناه."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"migrate_failed": "فشل إنشاء الجداول",
|
||||||
|
"database_variables_save_error": "غير قادر على الاتصال بقاعدة البيانات باستخدام القيم المقدمة.",
|
||||||
|
"mail_variables_save_error": "فشل تكوين البريد الإلكتروني.",
|
||||||
|
"connection_failed": "فشل اتصال قاعدة البيانات",
|
||||||
|
"database_should_be_empty": "يجب أن تكون قاعدة البيانات فارغة"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"mail_variables_save_successfully": "تم تكوين البريد الإلكتروني بنجاح",
|
||||||
|
"database_variables_save_successfully": "تم تكوين قاعدة البيانات بنجاح."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"layout_login": {
|
||||||
|
"copyright_crater": "حقوق الطبع والنشر @ كريتر - 2020",
|
||||||
|
"super_simple_invoicing": "فوترة سهلة ومبسطة للغاية",
|
||||||
|
"for_freelancer": "للمبرمجين المستقلين",
|
||||||
|
"small_businesses": "والأعال الصغيرة ",
|
||||||
|
"crater_help": "كريتر يساعدك على تتبع النفقات وتسجيل المدفوعات وإنشاء",
|
||||||
|
"invoices_and_estimates": "الفواتير والتقديرات مع إمكانية اختيار قوالب متعددة."
|
||||||
|
},
|
||||||
|
"validation": {
|
||||||
|
"invalid_url": "عنوان انترنت غير صحيح (مثال: http://www.crater.com)",
|
||||||
|
"required": "حقل مطلوب",
|
||||||
|
"email_incorrect": "بريد الكتروني غير صحيح.",
|
||||||
|
"email_already_taken": "هذا البريد الالكتروني مستخدم مسبقاً",
|
||||||
|
"email_does_not_exist": "لا يوجد كستخدم بهذا البريد الالكتروني",
|
||||||
|
"item_unit_already_taken": "وحدة البند قد اتخذت بالفعل",
|
||||||
|
"payment_mode_already_taken": "لقد تم بالفعل أخذ طريقة الدفع",
|
||||||
|
"send_reset_link": "أرسال رابط استعادة كلمة المرور",
|
||||||
|
"not_yet": "ليس بعد؟ أعد الإرسال الآن..",
|
||||||
|
"password_min_length": "كلمة المرور يجب أن تتكون من {count} أحرف على الأقل",
|
||||||
|
"name_min_length": "الاسم يجب أن يتكون من {count} أحرف على الأقل",
|
||||||
|
"enter_valid_tax_rate": "أدخل معدل الضريبة بشكل صحيح",
|
||||||
|
"numbers_only": "أرقام فقط.",
|
||||||
|
"characters_only": "حروف فقط.",
|
||||||
|
"password_incorrect": "يجب أن تكون كلمات المرور متطابقة",
|
||||||
|
"password_length": "يجب أن تكون كلمة المرور بطول {count} حرف.",
|
||||||
|
"qty_must_greater_than_zero": "الكمية يجب أن تكون أكبر من صفر.",
|
||||||
|
"price_greater_than_zero": "السعر يجب أن يكون أكبر من صفر.",
|
||||||
|
"payment_greater_than_zero": "الدفعة يجب أن تكون أكبر من صفر.",
|
||||||
|
"payment_greater_than_due_amount": "مبلغ الدفعة أكثر من المبلغ المستحق لهذه الفاتورة.",
|
||||||
|
"quantity_maxlength": "يجب ألا تزيد الكمية عن 20 رقماً.",
|
||||||
|
"price_maxlength": "يجب ألا يزيد السعر عن 20 رقماً.",
|
||||||
|
"price_minvalue": "يجب أن يكون السعر أكبر من صفر.",
|
||||||
|
"amount_maxlength": "يجب ألا يزيد المبلغ عن 20 رقماً.",
|
||||||
|
"amount_minvalue": "يجب أن يكون المبلغ أكبر من صفر.",
|
||||||
|
"description_maxlength": "يجب ألا يزيد الوصف عن 255 حرفاً.",
|
||||||
|
"maximum_options_error": "الحد الأعلى هو {max} خيارات. قم بإزالة أحد الخيارات لتحديد خيار آخر.",
|
||||||
|
"notes_maxlength": "يجب ألا يزيد حجم الملاحظات عن 255 حرفاً.",
|
||||||
|
"address_maxlength": "يجب ألا يزيد العنوان عن 255 حرفاً.",
|
||||||
|
"ref_number_maxlength": "يجب ألا يزيد الرقم المرجعي عن 255 حرفاً.",
|
||||||
|
"prefix_maxlength": "يجب ألا تزيد البادئة عن 5 أحرف."
|
||||||
|
}
|
||||||
|
}
|
||||||
919
resources/assets/js/plugins/de.json
Normal file
919
resources/assets/js/plugins/de.json
Normal file
@ -0,0 +1,919 @@
|
|||||||
|
{
|
||||||
|
"navigation": {
|
||||||
|
"dashboard": "Übersicht",
|
||||||
|
"customers": "Kunden",
|
||||||
|
"items": "Artikel",
|
||||||
|
"invoices": "Rechnungen",
|
||||||
|
"expenses": "Kosten",
|
||||||
|
"estimates": "Kostenvoranschläge",
|
||||||
|
"payments": "Zahlungen",
|
||||||
|
"reports": "Berichte",
|
||||||
|
"settings": "Einstellungen",
|
||||||
|
"logout": "Abmelden"
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"view_pdf": "PDF anzeigen",
|
||||||
|
"download_pdf": "PDF herunterladen",
|
||||||
|
"save": "Speichern",
|
||||||
|
"cancel": "Abrechen",
|
||||||
|
"update": "Aktualisieren",
|
||||||
|
"deselect": "Entfernen",
|
||||||
|
"download": "Herunterladen",
|
||||||
|
"from_date": "Von Datum",
|
||||||
|
"to_date": "bis Datum",
|
||||||
|
"from": "Von",
|
||||||
|
"to": "bis",
|
||||||
|
"sort_by": "Sortieren nach",
|
||||||
|
"ascending": "Aufsteigend",
|
||||||
|
"descending": "Absteigend",
|
||||||
|
"subject": "Betreff",
|
||||||
|
"message": "Nachricht",
|
||||||
|
"go_back": "zurück",
|
||||||
|
"back_to_login": "Zurück zum Login?",
|
||||||
|
"home": "Startseite",
|
||||||
|
"filter": "Filter",
|
||||||
|
"delete": "Löschen",
|
||||||
|
"edit": "Ändern",
|
||||||
|
"view": "Anzeigen",
|
||||||
|
"add_new_item": "Artikel hinzufügen",
|
||||||
|
"clear_all": "Alle entfernen",
|
||||||
|
"showing": "Anzeigen",
|
||||||
|
"of": "von",
|
||||||
|
"actions": "Aktionen",
|
||||||
|
"subtotal": "ZWISCHENSUMME",
|
||||||
|
"discount": "RABATT",
|
||||||
|
"fixed": "Behoben",
|
||||||
|
"percentage": "Prozentsatz",
|
||||||
|
"tax": "Steuer",
|
||||||
|
"total_amount": "GESAMTSUMME",
|
||||||
|
"bill_to": "Rechnungsempfänger",
|
||||||
|
"ship_to": "Versand ein",
|
||||||
|
"due": "Fällig",
|
||||||
|
"draft": "Entwurf",
|
||||||
|
"sent": "Gesendet",
|
||||||
|
"all": "Alle",
|
||||||
|
"select_all": "Alle auswählen",
|
||||||
|
"choose_file": "Klicken Sie hier, um eine Datei auszuwählen",
|
||||||
|
"choose_template": "Wählen Sie eine Vorlage",
|
||||||
|
"choose": "Wählen",
|
||||||
|
"remove": "Entfernen",
|
||||||
|
"powered_by": "Powered by",
|
||||||
|
"bytefury": "Bytefury",
|
||||||
|
"select_a_status": "Status wählen",
|
||||||
|
"select_a_tax": "Steuersatz wählen",
|
||||||
|
"search": "Suchen",
|
||||||
|
"are_you_sure": "Sind Sie sicher?",
|
||||||
|
"list_is_empty": "Liste ist leer.",
|
||||||
|
"no_tax_found": "Kein Steuersatz gefunden!",
|
||||||
|
"four_zero_four": "Vier hundert vier",
|
||||||
|
"you_got_lost": "Hoppla! Du hast dich verirrt!",
|
||||||
|
"go_home": "Geh zurück",
|
||||||
|
"test_mail_conf": "E-Mail Konfiguration testen",
|
||||||
|
"send_mail_successfully": "E-Mail versendet erfolgreich",
|
||||||
|
"setting_updated": "Einstellungen erfolgreich aktualisiert",
|
||||||
|
"select_state": "Bundesland wählen",
|
||||||
|
"select_country": "Land wählen",
|
||||||
|
"select_city": "Stadt wählen",
|
||||||
|
"street_1": "Straße",
|
||||||
|
"street_2": "Zusatz Strasse",
|
||||||
|
"action_failed": "Aktion fehlgeschlagen",
|
||||||
|
"retry": "Wiederholen"
|
||||||
|
},
|
||||||
|
"dashboard": {
|
||||||
|
"select_year": "Jahr wählen",
|
||||||
|
"cards": {
|
||||||
|
"due_amount": "Offene Beträge",
|
||||||
|
"customers": "Kunden",
|
||||||
|
"invoices": "Rechnungen",
|
||||||
|
"estimates": "Kostenvoranschläge"
|
||||||
|
},
|
||||||
|
"chart_info": {
|
||||||
|
"total_sales": "Verkäufe gesamt",
|
||||||
|
"total_receipts": "Eingänge gesamt",
|
||||||
|
"total_expense": "Gesamtausgaben",
|
||||||
|
"net_income": "Einnahmen Netto",
|
||||||
|
"year": "Jahr"
|
||||||
|
},
|
||||||
|
"weekly_invoices": {
|
||||||
|
"title": "Wöchentliche Rechnungen"
|
||||||
|
},
|
||||||
|
"monthly_chart": {
|
||||||
|
"title": "Umsatz & Kosten"
|
||||||
|
},
|
||||||
|
"recent_invoices_card": {
|
||||||
|
"title": "Fällige Rechnungen",
|
||||||
|
"due_on": "Fällig am",
|
||||||
|
"customer": "Kunden",
|
||||||
|
"amount_due": "Offener Betrag",
|
||||||
|
"actions": "Aktionen",
|
||||||
|
"view_all": "Alle Anzeigen"
|
||||||
|
},
|
||||||
|
"recent_estimate_card": {
|
||||||
|
"title": "Aktuelle Kostenvoranschläge",
|
||||||
|
"date": "Datum",
|
||||||
|
"customer": "Kunden",
|
||||||
|
"amount_due": "Betrag",
|
||||||
|
"actions": "Aktionen",
|
||||||
|
"view_all": "Alle Anzeigen"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tax_types": {
|
||||||
|
"name": "Name",
|
||||||
|
"description": "Beschreibung",
|
||||||
|
"percent": "Prozent",
|
||||||
|
"compound_tax": "zusammengesetzte Steuer"
|
||||||
|
},
|
||||||
|
"customers": {
|
||||||
|
"title": "Kunden",
|
||||||
|
"add_customer": "Kunde hinzufügen",
|
||||||
|
"contacts_list": "Kunden-Liste",
|
||||||
|
"name": "Name",
|
||||||
|
"display_name": "Anzeige Name",
|
||||||
|
"primary_contact_name": "Ansprechpartner",
|
||||||
|
"contact_name": "Kontakt Name",
|
||||||
|
"amount_due": "Offener Betrag",
|
||||||
|
"email": "E-Mail",
|
||||||
|
"address": "Adresse",
|
||||||
|
"phone": "Telefon",
|
||||||
|
"website": "Webseite",
|
||||||
|
"country": "Land",
|
||||||
|
"state": "Bundesland",
|
||||||
|
"city": "Stadt",
|
||||||
|
"zip_code": "PLZ",
|
||||||
|
"added_on": "Hinzugefügt am",
|
||||||
|
"action": "Aktion",
|
||||||
|
"password": "Passwort",
|
||||||
|
"street_number": "Hausnummer",
|
||||||
|
"primary_currency": "Primäre Währung",
|
||||||
|
"add_new_customer": "Neuen Kunden hinzufügen",
|
||||||
|
"save_customer": "Kunde speichern",
|
||||||
|
"update_customer": "Kunden ändern",
|
||||||
|
"customer": "Kunde | Kunden",
|
||||||
|
"new_customer": "Neuer Kunde",
|
||||||
|
"edit_customer": "Kunde bearbeiten",
|
||||||
|
"basic_info": "Basisinformation",
|
||||||
|
"billing_address": "Rechnungsadresse",
|
||||||
|
"shipping_address": "Versand-Adresse",
|
||||||
|
"copy_billing_address": "Rechnungsadresse kopieren",
|
||||||
|
"no_customers": "Noch keine Kunden!",
|
||||||
|
"no_customers_found": "Keine Kunden gefunden!",
|
||||||
|
"list_of_customers": "Dieser Abschnitt enthält die Liste der Kunden.",
|
||||||
|
"primary_display_name": "Primärer Anzeige Name",
|
||||||
|
"select_currency": "Währung wählen",
|
||||||
|
"select_a_customer": "Wählen Sie einen Kunden",
|
||||||
|
"type_or_click": "Eingeben oder anklicken zum auswählen",
|
||||||
|
"confirm_delete": "Sie können diesen Kunden und alle zugehörigen Rechnungen, Schätzungen und Zahlungen nicht wiederherstellen. | Sie können diesen Kunden und alle zugehörigen Rechnungen, Schätzungen und Zahlungen nicht wiederherstellen.",
|
||||||
|
"updated_message": "Kunde erfolgreich aktualisiert",
|
||||||
|
"deleted_message": "Kunden erfolgreich gelöscht | Kunden erfolgreich gelöscht"
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"title": "Artikel",
|
||||||
|
"items_list": "Artikel-Liste",
|
||||||
|
"name": "Name",
|
||||||
|
"unit": "Einheit",
|
||||||
|
"description": "Beschreibung",
|
||||||
|
"added_on": "Hinzugefügt am",
|
||||||
|
"price": "Preis",
|
||||||
|
"date_of_creation": "Erstellt am",
|
||||||
|
"action": "Aktion",
|
||||||
|
"add_item": "Artikel hinzufügen",
|
||||||
|
"save_item": "Artikel speichern",
|
||||||
|
"update_item": "Artikel ändern",
|
||||||
|
"item": "Artikel | Artikel",
|
||||||
|
"add_new_item": "Neuen Artikel hinzufügen",
|
||||||
|
"new_item": "Neuer Artikel",
|
||||||
|
"edit_item": "Artikel bearbeiten",
|
||||||
|
"no_items": "Keine Artikel vorhanden!",
|
||||||
|
"list_of_items": "Dieser Abschnitt enthält die Liste der Artikel.",
|
||||||
|
"select_a_unit": "wählen Sie die Einheit",
|
||||||
|
"taxes": "Steuern",
|
||||||
|
"item_attached_message": "Ein Artikel der bereits verwendet wird kann nicht gelöscht werden",
|
||||||
|
"confirm_delete": "Sie können diesen Artikel nicht wiederherstellen | Sie können diese Artikel nicht wiederherstellen",
|
||||||
|
"created_message": "Artikel erfolgreich erstellt",
|
||||||
|
"updated_message": "Artikel erfolgreich aktualisiert",
|
||||||
|
"deleted_message": "Artikel erfolgreich gelöscht | Artikel erfolgreich gelöscht"
|
||||||
|
},
|
||||||
|
"estimates": {
|
||||||
|
"title": "Kostenvoranschläge",
|
||||||
|
"estimate": "Kostenvoranschlag | Kostenvoranschläge",
|
||||||
|
"estimates_list": "Liste Kostenvoranschläge",
|
||||||
|
"days": "{days} Tage",
|
||||||
|
"months": "{months} Monat",
|
||||||
|
"years": "{years} Jahre",
|
||||||
|
"all": "Alle",
|
||||||
|
"paid": "Bezahlt",
|
||||||
|
"unpaid": "Unbezahlte",
|
||||||
|
"customer": "KUNDEN",
|
||||||
|
"ref_no": "REF. - NR.",
|
||||||
|
"number": "ANZAHL",
|
||||||
|
"amount_due": "OFFENER BETRAG",
|
||||||
|
"partially_paid": "Teilweise bezahlt",
|
||||||
|
"total": "Gesamt",
|
||||||
|
"discount": "Rabatt",
|
||||||
|
"sub_total": "Zwischensumme",
|
||||||
|
"estimate_number": "Kostenvoran. Nummer",
|
||||||
|
"ref_number": "Ref-Nummer",
|
||||||
|
"contact": "Kontakt",
|
||||||
|
"add_item": "Fügen Sie ein Artikel hinzu",
|
||||||
|
"date": "Datum",
|
||||||
|
"due_date": "Fälligkeit",
|
||||||
|
"expiry_date": "Zahlungsziel",
|
||||||
|
"status": "Status",
|
||||||
|
"add_tax": "Steuer hinzufügen",
|
||||||
|
"amount": "Summe",
|
||||||
|
"action": "Aktion",
|
||||||
|
"notes": "Hinweise",
|
||||||
|
"tax": "Steuer",
|
||||||
|
"estimate_template": "Vorlage",
|
||||||
|
"convert_to_invoice": "Konvertieren in Rechnung",
|
||||||
|
"mark_as_sent": "Als gesendet markieren",
|
||||||
|
"send_estimate": "Kostenvoranschlag senden",
|
||||||
|
"record_payment": "Zahlung erfassen",
|
||||||
|
"add_estimate": "Kostenvoranschlag hinzufügen",
|
||||||
|
"save_estimate": "Kostenvoranschlag speichern",
|
||||||
|
"confirm_conversion": "Sie möchten, konvertieren Sie diese Schätzung in die Rechnung?",
|
||||||
|
"conversion_message": "Rechnung erfolgreich erstellt",
|
||||||
|
"confirm_send_estimate": "Der Kostenvoranschlag wird per E-Mail an den Kunden gesendet",
|
||||||
|
"confirm_mark_as_sent": "Dieser Kostenvoranschlag wird als gesendet markiert",
|
||||||
|
"confirm_mark_as_accepted": "Dieser Kostenvoranschlag wird als angenommen markiert",
|
||||||
|
"confirm_mark_as_rejected": "Dieser Kostenvoranschlag wird als abgelehnt markiert",
|
||||||
|
"no_matching_estimates": "Es gibt keine übereinstimmenden Kostenvoranschläge!",
|
||||||
|
"mark_as_sent_successfully": "Kostenvoranschlag als gesendet markiert.",
|
||||||
|
"send_estimate_successfully": "Kostenvoranschlag erfolgreich gesendet",
|
||||||
|
"errors": {
|
||||||
|
"required": "Feld ist erforderlich"
|
||||||
|
},
|
||||||
|
"accepted": "Angenommen",
|
||||||
|
"sent": "Gesendet",
|
||||||
|
"draft": "Entwurf",
|
||||||
|
"declined": "Abgelehnt",
|
||||||
|
"new_estimate": "Neuer Kostenvoranschlag",
|
||||||
|
"add_new_estimate": "Neuen Kostenvoranschlag hinzufügen",
|
||||||
|
"update_Estimate": "Kostenvoranschlag aktualisieren",
|
||||||
|
"edit_estimate": "Kostenvoranschlag ändern",
|
||||||
|
"items": "Artikel",
|
||||||
|
"Estimate": "Kostenvoranschlag | Kostenvoranschläge",
|
||||||
|
"add_new_tax": "neuen Steuersatz hinzufügen",
|
||||||
|
"no_estimates": "Keine Kostenvoranschläge vorhanden!",
|
||||||
|
"list_of_estimates": "Dieser Abschnitt enthält die Liste der Kostenvoranschläge.",
|
||||||
|
"mark_as_rejected": "Markiert als abgelehnt",
|
||||||
|
"mark_as_accepted": "Markiert als angenommen",
|
||||||
|
"marked_as_accepted_message": "Kostenvoranschlag als angenommen markiert",
|
||||||
|
"marked_as_rejected_message": "Kostenvoranschlag als abgelehnt markiert",
|
||||||
|
"confirm_delete": "Der Kostenvoranschlag kann nicht wiederhergestellt werden | Die Kostenvoranschläge können nicht wiederhergestellt werden",
|
||||||
|
"created_message": "Kostenvoranschlag erfolgreich erstellt",
|
||||||
|
"updated_message": "Kostenvoranschlag erfolgreich aktualisiert",
|
||||||
|
"deleted_message": "Kostenvoranschlag erfolgreich gelöscht | Kostenvoranschläge erfolgreich gelöscht",
|
||||||
|
"user_email_does_not_exist": "Benutzer-E-Mail nicht vorhanden",
|
||||||
|
"something_went_wrong": "Da ging etwas schief",
|
||||||
|
"item": {
|
||||||
|
"title": "Titel",
|
||||||
|
"description": "Beschreibung",
|
||||||
|
"quantity": "Menge",
|
||||||
|
"price": "Preis",
|
||||||
|
"discount": "Rabatt",
|
||||||
|
"total": "Gesamt",
|
||||||
|
"total_discount": "Rabatt Gesamt",
|
||||||
|
"sub_total": "Zwischensumme",
|
||||||
|
"tax": "Steuer",
|
||||||
|
"amount": "Summe",
|
||||||
|
"select_an_item": "Wählen Sie einen Artikel",
|
||||||
|
"type_item_description": "Artikel Beschreibung (optional)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"invoices": {
|
||||||
|
"title": "Rechnungen",
|
||||||
|
"invoices_list": "Liste der Rechnungen",
|
||||||
|
"days": "{days} Tage",
|
||||||
|
"months": "{months} Monat",
|
||||||
|
"years": "{years} Jahre",
|
||||||
|
"all": "Alle",
|
||||||
|
"paid": "Bezahlt",
|
||||||
|
"unpaid": "Unbezahlte",
|
||||||
|
"customer": "KUNDEN",
|
||||||
|
"paid_status": "BEZAHLT-STATUS",
|
||||||
|
"ref_no": "REF. - NR.",
|
||||||
|
"number": "ANZAHL",
|
||||||
|
"amount_due": "OFFENER BETRAG",
|
||||||
|
"partially_paid": "Teilzahlung",
|
||||||
|
"total": "Gesamt",
|
||||||
|
"discount": "Rabatt",
|
||||||
|
"sub_total": "Zwischensumme",
|
||||||
|
"invoice": "Rechnung | Rechnungen",
|
||||||
|
"invoice_number": "Rechnungsnummer",
|
||||||
|
"ref_number": "Ref-Nummer",
|
||||||
|
"contact": "Kontakt",
|
||||||
|
"add_item": "Fügen Sie ein Artikel hinzu",
|
||||||
|
"date": "Datum",
|
||||||
|
"due_date": "Fälligkeit",
|
||||||
|
"status": "Status",
|
||||||
|
"add_tax": "Steuersatz hinzufügen",
|
||||||
|
"amount": "Summe",
|
||||||
|
"action": "Aktion",
|
||||||
|
"notes": "Hinweise",
|
||||||
|
"view": "Anzeigen",
|
||||||
|
"send_invoice": "Rechnung senden",
|
||||||
|
"invoice_template": "Rechnungs-Vorlage",
|
||||||
|
"template": "Vorlage",
|
||||||
|
"mark_as_sent": "Als gesendet markieren",
|
||||||
|
"confirm_send_invoice": "Diese Rechnung wird per E-Mail an den Kunden gesendet",
|
||||||
|
"invoice_mark_as_sent": "Diese Rechnung wird als gesendet markiert",
|
||||||
|
"confirm_send": "Diese Rechnung wird per E-Mail an den Kunden gesendet",
|
||||||
|
"invoice_date": "Rechnungsdatum",
|
||||||
|
"record_payment": "Zahlung erfassen",
|
||||||
|
"add_new_invoice": "Neue Rechnung hinzufügen",
|
||||||
|
"update_expense": "Kosten aktualisieren",
|
||||||
|
"edit_invoice": "Rechnung bearbeiten",
|
||||||
|
"new_invoice": "Neue Rechnung",
|
||||||
|
"save_invoice": "Rechnung speichern",
|
||||||
|
"update_invoice": "Rechnung ändern",
|
||||||
|
"add_new_tax": "Neuen Steuersatz hinzufügen",
|
||||||
|
"no_invoices": "Keine Rechnungen vorhanden!",
|
||||||
|
"list_of_invoices": "Dieser Abschnitt enthält die Liste der Rechnungen.",
|
||||||
|
"select_invoice": "Wählen Sie eine Rechnung",
|
||||||
|
"no_matching_invoices": "Es gibt keine entsprechenden Rechnungen!",
|
||||||
|
"mark_as_sent_successfully": "Rechnung gekennzeichnet als erfolgreich gesendet",
|
||||||
|
"send_invoice_successfully": "Rechnung erfolgreich versendet",
|
||||||
|
"cloned_successfully": "Rechnung erfolgreich kopiert",
|
||||||
|
"clone_invoice": "Rechnung kopieren",
|
||||||
|
"confirm_clone": "Diese Rechnung wird kopiert",
|
||||||
|
"item": {
|
||||||
|
"title": "Titel",
|
||||||
|
"description": "Beschreibung",
|
||||||
|
"quantity": "Menge",
|
||||||
|
"price": "Preis",
|
||||||
|
"discount": "Rabatt",
|
||||||
|
"total": "Gesamt",
|
||||||
|
"total_discount": "Rabatt Gesamt",
|
||||||
|
"sub_total": "Zwischensumme",
|
||||||
|
"tax": "Steuer",
|
||||||
|
"amount": "Summe",
|
||||||
|
"select_an_item": "Geben Sie oder wählen Sie ein Artikel",
|
||||||
|
"type_item_description": "Artikel Beschreibung (optional)"
|
||||||
|
},
|
||||||
|
"payment_attached_message": "Einer der ausgewählten Rechnungen ist bereits eine Zahlung zugeordnet. Stellen Sie sicher, dass Sie zuerst die angehängten Zahlungen löschen, um mit dem Entfernen fortzufahren",
|
||||||
|
"confirm_delete": "Sie können diese Rechnung nicht wiederherstellen. | Sie können diese Rechnungen nicht wiederherstellen.",
|
||||||
|
"created_message": "Rechnung erfolgreich erstellt",
|
||||||
|
"updated_message": "Rechnung erfolgreich aktualisiert",
|
||||||
|
"deleted_message": "Rechnung erfolgreich gelöscht | Rechnungen erfolgreich gelöscht",
|
||||||
|
"marked_as_sent_message": "Rechnung als erfolgreich gesendet markiert",
|
||||||
|
"user_email_does_not_exist": "Benutzer-E-Mail existiert nicht",
|
||||||
|
"something_went_wrong": "Da ist etwas schief gelaufen",
|
||||||
|
"invalid_due_amount_message": "Der Gesamtrechnungsbetrag darf nicht kleiner sein als der für diese Rechnung bezahlte Gesamtbetrag. Bitte aktualisieren Sie die Rechnung oder löschen Sie die zugehörigen Zahlungen um fortzufahren."
|
||||||
|
},
|
||||||
|
"credit_notes": {
|
||||||
|
"title": "Gutschriften",
|
||||||
|
"credit_notes_list": "Gutschriften-Liste",
|
||||||
|
"credit_notes": "Gutschriften",
|
||||||
|
"contact": "Kontakt",
|
||||||
|
"date": "Datum",
|
||||||
|
"amount": "Summe",
|
||||||
|
"action": "Aktion",
|
||||||
|
"credit_number": "Kreditkarten-Nummer",
|
||||||
|
"notes": "Hinweise",
|
||||||
|
"confirm_delete": "Wollen Sie diese Gutschrift löschen?",
|
||||||
|
"item": {
|
||||||
|
"title": "Titel",
|
||||||
|
"description": "Beschreibung",
|
||||||
|
"quantity": "Menge",
|
||||||
|
"price": "Preis",
|
||||||
|
"discount": "Rabatt",
|
||||||
|
"total": "Gesamt",
|
||||||
|
"total_discount": "Rabatt Gesamt",
|
||||||
|
"sub_total": "Zwischensumme",
|
||||||
|
"tax": "Steuer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"payments": {
|
||||||
|
"title": "Zahlungen",
|
||||||
|
"payments_list": "Liste der Zahlungen",
|
||||||
|
"record_payment": "Zahlung eintragen",
|
||||||
|
"customer": "Kunden",
|
||||||
|
"date": "Datum",
|
||||||
|
"amount": "Summe",
|
||||||
|
"action": "Aktion",
|
||||||
|
"payment_number": "Zahlungsnummer",
|
||||||
|
"payment_mode": "Zahlungsart",
|
||||||
|
"invoice": "Rechnung",
|
||||||
|
"note": "Hinweis",
|
||||||
|
"add_payment": "Zahlung hinzufügen",
|
||||||
|
"new_payment": "Neue Zahlung",
|
||||||
|
"edit_payment": "Zahlung bearbeiten",
|
||||||
|
"view_payment": "Zahlung anzeigen",
|
||||||
|
"add_new_payment": "Neue Zahlung hinzufügen",
|
||||||
|
"send_payment_receipt": "Send Payment Receipt",
|
||||||
|
"save_payment": "Zahlung speichern",
|
||||||
|
"update_payment": "Zahlung ändern",
|
||||||
|
"payment": "Zahlung | Zahlungen",
|
||||||
|
"no_payments": "Keine Zahlungen vorhanden!",
|
||||||
|
"no_matching_payments": "Es gibt keine passenden Zahlungen!",
|
||||||
|
"list_of_payments": "Dieser Abschnitt enthält die Liste der Zahlungen.",
|
||||||
|
"select_payment_mode": "Wählen Sie den Zahlungsmodus",
|
||||||
|
"confirm_send_payment": "This payment will be sent via email to the customer",
|
||||||
|
"send_payment_successfully": "Payment sent successfully",
|
||||||
|
"user_email_does_not_exist": "User email does not exist",
|
||||||
|
"something_went_wrong": "something went wrong",
|
||||||
|
"confirm_delete": "Sie können diese Zahlung nicht wiederherstellen. | Sie können diese Zahlungen nicht wiederherstellen.",
|
||||||
|
"created_message": "Zahlung erfolgreich erstellt",
|
||||||
|
"updated_message": "Zahlung erfolgreich aktualisiert",
|
||||||
|
"deleted_message": "Zahlung erfolgreich gelöscht | Zahlungen erfolgreich gelöscht",
|
||||||
|
"invalid_amount_message": "Zahlungsbetrag ist ungültig"
|
||||||
|
},
|
||||||
|
"expenses": {
|
||||||
|
"title": "Aufwendungen/Ausgaben",
|
||||||
|
"expenses_list": "Liste der Ausgaben",
|
||||||
|
"expense_title": "Titel",
|
||||||
|
"contact": "Kontakt",
|
||||||
|
"category": "Kategorie",
|
||||||
|
"from_date": "Von Datum",
|
||||||
|
"to_date": "bis Datum",
|
||||||
|
"expense_date": "Datum",
|
||||||
|
"description": "Beschreibung",
|
||||||
|
"receipt": "Eingang",
|
||||||
|
"amount": "Summe",
|
||||||
|
"action": "Aktion",
|
||||||
|
"note": "Hinweis",
|
||||||
|
"category_id": "Kategorie-Id",
|
||||||
|
"date": "Aufwandsdatum",
|
||||||
|
"add_expense": "Aufwendung hinzufügen",
|
||||||
|
"add_new_expense": "Neue Aufwendung hinzufügen",
|
||||||
|
"save_expense": "Aufwendung speichern",
|
||||||
|
"update_expense": "Aufwendung aktualisieren",
|
||||||
|
"download_receipt": "Quittung herunterladen",
|
||||||
|
"edit_expense": "Aufwendung ändern",
|
||||||
|
"new_expense": "Neue Aufwendung",
|
||||||
|
"expense": "Aufwendung | Aufwendungen",
|
||||||
|
"no_expenses": "Noch keine Ausgaben!",
|
||||||
|
"list_of_expenses": "Dieser Abschnitt enthält die Liste der Ausgaben.",
|
||||||
|
"confirm_delete": "Sie können diese Ausgabe nicht wiederherstellen. | Sie können diese Ausgaben nicht wiederherstellen.",
|
||||||
|
"created_message": "Aufwand erfolgreich erstellt",
|
||||||
|
"updated_message": "Aufwand erfolgreich aktualisiert",
|
||||||
|
"deleted_message": "Aufwand erfolgreich gelöscht | Aufwand erfolgreich gelöscht",
|
||||||
|
"categories": {
|
||||||
|
"categories_list": "Liste der Kategorien",
|
||||||
|
"title": "Titel",
|
||||||
|
"name": "Name",
|
||||||
|
"description": "Beschreibung",
|
||||||
|
"amount": "Summe",
|
||||||
|
"actions": "Aktionen",
|
||||||
|
"add_category": "Kategorie hinzufügen",
|
||||||
|
"new_category": "Neue Kategorie",
|
||||||
|
"category": "Kategorie | Kategorien",
|
||||||
|
"select_a_category": "Wählen Sie eine Kategorie"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"login": {
|
||||||
|
"email": "E-Mail",
|
||||||
|
"password": "Passwort",
|
||||||
|
"forgot_password": "Passwort vergessen?",
|
||||||
|
"or_signIn_with": "oder Anmelden mit",
|
||||||
|
"login": "Anmelden",
|
||||||
|
"register": "Registrieren",
|
||||||
|
"reset_password": "Passwort zurücksetzen",
|
||||||
|
"password_reset_successfully": "Passwort erfolgreich zurückgesetzt",
|
||||||
|
"enter_email": "Geben Sie Ihre E-Mail ein",
|
||||||
|
"enter_password": "Geben Sie das Passwort ein",
|
||||||
|
"retype_password": "Passwort bestätigen",
|
||||||
|
"login_placeholder": "mail@beispiel.de"
|
||||||
|
},
|
||||||
|
"reports": {
|
||||||
|
"title": "Bericht",
|
||||||
|
"from_date": "Ab Datum",
|
||||||
|
"to_date": "bis Datum",
|
||||||
|
"status": "Status",
|
||||||
|
"paid": "Bezahlt",
|
||||||
|
"unpaid": "Unbezahlt",
|
||||||
|
"download_pdf": "PDF herunterladen",
|
||||||
|
"view_pdf": "PDF anzeigen",
|
||||||
|
"update_report": "Bericht aktualisieren",
|
||||||
|
"report": "Bericht | Berichte",
|
||||||
|
"profit_loss": {
|
||||||
|
"profit_loss": "Gewinn & Verlust",
|
||||||
|
"to_date": "bis Datum",
|
||||||
|
"from_date": "Ab Datum",
|
||||||
|
"date_range": "Datumsbereich auswählen"
|
||||||
|
},
|
||||||
|
"sales": {
|
||||||
|
"sales": "Vertrieb",
|
||||||
|
"date_range": "Datumsbereich auswählen",
|
||||||
|
"to_date": "bis Datum",
|
||||||
|
"from_date": "Ab Datum",
|
||||||
|
"report_type": "Berichtstyp"
|
||||||
|
},
|
||||||
|
"taxes": {
|
||||||
|
"taxes": "Steuern",
|
||||||
|
"to_date": "bis Datum",
|
||||||
|
"from_date": "Ab Datum",
|
||||||
|
"date_range": "Datumsbereich auswählen"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"required": "Feld ist erforderlich"
|
||||||
|
},
|
||||||
|
"invoices": {
|
||||||
|
"invoice": "Rechnung",
|
||||||
|
"invoice_date": "Rechnungsdatum",
|
||||||
|
"due_date": "Fälligkeit",
|
||||||
|
"amount": "Summe",
|
||||||
|
"contact_name": "Ansprechpartner",
|
||||||
|
"status": "Status"
|
||||||
|
},
|
||||||
|
"estimates": {
|
||||||
|
"estimate": "Kostenvoranschlag",
|
||||||
|
"estimate_date": "Datum Kostenvoranschlag",
|
||||||
|
"due_date": "Fälligkeit",
|
||||||
|
"estimate_number": "Kostenvoranschlag-Nr.",
|
||||||
|
"ref_number": "Ref-Nummer",
|
||||||
|
"amount": "Summe",
|
||||||
|
"contact_name": "Ansprechpartner",
|
||||||
|
"status": "Status"
|
||||||
|
},
|
||||||
|
"expenses": {
|
||||||
|
"expenses": "Aufwendungen",
|
||||||
|
"category": "Kategorie",
|
||||||
|
"date": "Datum",
|
||||||
|
"amount": "Summe",
|
||||||
|
"to_date": "bis Datum",
|
||||||
|
"from_date": "Ab Datum",
|
||||||
|
"date_range": "Datumsbereich auswählen"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"menu_title": {
|
||||||
|
"account_settings": "Konto-Einstellungen",
|
||||||
|
"company_information": "Informationen zum Unternehmen",
|
||||||
|
"customization": "Anpassung",
|
||||||
|
"preferences": "Einstellungen",
|
||||||
|
"notifications": "Benachrichtigungen",
|
||||||
|
"tax_types": "Steuersätze",
|
||||||
|
"expense_category": "Ausgabenkategorien",
|
||||||
|
"update_app": "Applikation aktualisieren"
|
||||||
|
},
|
||||||
|
"title": "Einstellungen",
|
||||||
|
"setting": "Einstellung | Einstellungen",
|
||||||
|
"general": "Allgemeine",
|
||||||
|
"language": "Sprache",
|
||||||
|
"primary_currency": "Primäre Währung",
|
||||||
|
"timezone": "Zeitzone",
|
||||||
|
"date_format": "Datum-Format",
|
||||||
|
"currencies": {
|
||||||
|
"title": "Währungen",
|
||||||
|
"currency": "Währung | Währungen",
|
||||||
|
"currencies_list": "Währungen Liste",
|
||||||
|
"select_currency": "Währung wählen",
|
||||||
|
"name": "Name",
|
||||||
|
"code": "Code",
|
||||||
|
"symbol": "Symbol",
|
||||||
|
"precision": "Präzision",
|
||||||
|
"thousand_separator": "Tausendertrennzeichen",
|
||||||
|
"decimal_separator": "Dezimal-Trennzeichen",
|
||||||
|
"position": "Position",
|
||||||
|
"position_of_symbol": "Position des Währungssymbol",
|
||||||
|
"right": "Rechts",
|
||||||
|
"left": "Links",
|
||||||
|
"action": "Aktion",
|
||||||
|
"add_currency": "Währung einfügen"
|
||||||
|
},
|
||||||
|
"mail": {
|
||||||
|
"host": "E-Mail Mailserver",
|
||||||
|
"port": "E-Mail Port",
|
||||||
|
"driver": "E-Mail Treiber",
|
||||||
|
"secret": "Verschlüsselung",
|
||||||
|
"mailgun_secret": "Mailgun Verschlüsselung",
|
||||||
|
"mailgun_domain": "Domain",
|
||||||
|
"mailgun_endpoint": "Mailgun-Endpunkt",
|
||||||
|
"ses_secret": "SES Verschlüsselung",
|
||||||
|
"ses_key": "SES-Taste",
|
||||||
|
"password": "E-Mail-Kennwort",
|
||||||
|
"username": "E-Mail-Benutzername",
|
||||||
|
"mail_config": "E-Mail-Konfiguration",
|
||||||
|
"from_name": "Von E-Mail-Namen",
|
||||||
|
"from_mail": "Von E-Mail-Adresse",
|
||||||
|
"encryption": "E-Mail-Verschlüsselung",
|
||||||
|
"mail_config_desc": "Unten finden Sie das Formular zum Konfigurieren des E-Mail-Treibers zum Senden von E-Mails über die App. Sie können auch Drittanbieter wie Sendgrid, SES usw. konfigurieren."
|
||||||
|
},
|
||||||
|
"pdf": {
|
||||||
|
"title": "PDF-Einstellung",
|
||||||
|
"footer_text": "Fußzeile Text",
|
||||||
|
"pdf_layout": "PDF-Layout"
|
||||||
|
},
|
||||||
|
"company_info": {
|
||||||
|
"company_info": "Firmeninfo",
|
||||||
|
"company_name": "Name des Unternehmens",
|
||||||
|
"company_logo": "Firmenlogo",
|
||||||
|
"section_description": "Informationen zu Ihrem Unternehmen, die auf Rechnungen, Kostenvoranschlägen und anderen von Crater erstellten Dokumenten angezeigt werden.",
|
||||||
|
"phone": "Telefon",
|
||||||
|
"country": "Land",
|
||||||
|
"state": "Bundesland",
|
||||||
|
"city": "Stadt",
|
||||||
|
"address": "Adresse",
|
||||||
|
"zip": "PLZ",
|
||||||
|
"save": "Speichern",
|
||||||
|
"updated_message": "Unternehmensinformationen wurden erfolgreich aktualisiert"
|
||||||
|
},
|
||||||
|
"customization": {
|
||||||
|
"customization": "Anpassung",
|
||||||
|
"save": "Speichern",
|
||||||
|
"addresses": {
|
||||||
|
"title": "Adressen",
|
||||||
|
"section_description": "Sie können die Rechnungsadresse und das Versandadressenformat des Kunden festlegen (nur in PDF angezeigt). ",
|
||||||
|
"customer_billing_address": "Rechnungsadresse des Kunden",
|
||||||
|
"customer_shipping_address": "Versand-Adresse des Kunden",
|
||||||
|
"company_address": "Firma Adresse",
|
||||||
|
"insert_fields": "Felder einfügen",
|
||||||
|
"contact": "Kontakt",
|
||||||
|
"address": "Adresse",
|
||||||
|
"display_name": "Anzeigename",
|
||||||
|
"primary_contact_name": "Ansprechpartner",
|
||||||
|
"email": "E-Mail",
|
||||||
|
"website": "Website",
|
||||||
|
"name": "Name",
|
||||||
|
"country": "Land",
|
||||||
|
"state": "Bundesland",
|
||||||
|
"city": "Stadt",
|
||||||
|
"company_name": "Name des Unternehmens",
|
||||||
|
"address_street_1": "Strasse",
|
||||||
|
"address_street_2": "Zusatz Strasse",
|
||||||
|
"phone": "Telefon",
|
||||||
|
"zip_code": "PLZ",
|
||||||
|
"address_setting_updated": "Adresse-Einstellung erfolgreich aktualisiert"
|
||||||
|
},
|
||||||
|
"updated_message": "Unternehmensinformationen wurden erfolgreich aktualisiert",
|
||||||
|
"invoices": {
|
||||||
|
"title": "Rechnungen",
|
||||||
|
"notes": "Hinweise",
|
||||||
|
"invoice_prefix": "Rechnung Präfix",
|
||||||
|
"invoice_settings": "Rechnungseinstellungen",
|
||||||
|
"autogenerate_invoice_number": "Rechnungsnummer automatisch generieren",
|
||||||
|
"invoice_setting_description": "Deaktivieren Sie diese Option, wenn Sie Rechnungsnummern nicht jedes Mal automatisch generieren möchten, wenn Sie eine neue Rechnung erstellen.",
|
||||||
|
"enter_invoice_prefix": "Rechnungspräfix eingeben",
|
||||||
|
"terms_and_conditions": "Allgemeine Geschäftsbedingungen",
|
||||||
|
"invoice_setting_updated": "Rechnungseinstellung erfolgreich aktualisiert"
|
||||||
|
},
|
||||||
|
"estimates": {
|
||||||
|
"title": "Kostenvoranschläge",
|
||||||
|
"estimate_prefix": "Kostenvoranschlag Präfix",
|
||||||
|
"estimate_settings": "Einstellungen Kostenvoranschlag",
|
||||||
|
"autogenerate_estimate_number": "Kostenvoranschlagsnummer automatisch generieren",
|
||||||
|
"estimate_setting_description": "Deaktivieren Sie diese Option, wenn Sie nicht jedes Mal, wenn Sie einen neue Kostenvoranschlag erstellen, automatisch eine Schätzung generieren möchten.",
|
||||||
|
"enter_estimate_prefix": "Geben Sie das Kostenvoranschlag Präfix ein",
|
||||||
|
"estimate_setting_updated": "Einstellungen Kostenvoranschläge erfolgreich aktualisiert"
|
||||||
|
},
|
||||||
|
"payments": {
|
||||||
|
"title": "Zahlungen",
|
||||||
|
"payment_prefix": "Zahlung Präfix",
|
||||||
|
"payment_settings": "Zahlung Einstellungen",
|
||||||
|
"autogenerate_payment_number": "Zahlungsnummer automatisch generieren",
|
||||||
|
"payment_setting_description": "Deaktivieren Sie diese Option, wenn Sie nicht jedes Mal, wenn Sie eine neue Zahlung erstellen, automatisch Zahlungsnummern generieren möchten.",
|
||||||
|
"enter_payment_prefix": "Zahlungspräfix eingeben",
|
||||||
|
"payment_setting_updated": "Zahlungseinstellung erfolgreich aktualisiert",
|
||||||
|
"payment_mode": "Zahlungsmethode",
|
||||||
|
"add_payment_mode": "Zahlungsmethode hinzufügen",
|
||||||
|
"mode_name": "Methodenname",
|
||||||
|
"payment_mode_added": "Zahlungsmethode hinzugefügt",
|
||||||
|
"payment_mode_updated": "Zahlungsmethode aktualisiert",
|
||||||
|
"payment_mode_confirm_delete": "Du kannst diese Zahlungsmethode nicht wiederherstellen",
|
||||||
|
"already_in_use": "Zahlungsmethode bereits in Verwendung",
|
||||||
|
"deleted_message": "Zahlungsmethode erfolgreich"
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"title": "Artikel",
|
||||||
|
"units": "Einheiten",
|
||||||
|
"add_item_unit": "Artikeleinheit hinzufügen",
|
||||||
|
"unit_name": "Einheitname",
|
||||||
|
"item_unit_added": "Artikeleinheit hinzugefügt",
|
||||||
|
"item_unit_updated": "Artikeleinheit aktualisiert",
|
||||||
|
"item_unit_confirm_delete": "Du kannst diese Artikeleinheit nicht wiederherstellen",
|
||||||
|
"already_in_use": "Diese Artikeleinheit ist bereits in Verwendung",
|
||||||
|
"deleted_message": "Artikeleinheit erfolgreich gelöscht"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"account_settings": {
|
||||||
|
"profile_picture": "Profil Bild",
|
||||||
|
"name": "Name",
|
||||||
|
"email": "E-Mail",
|
||||||
|
"password": "Passwort",
|
||||||
|
"confirm_password": "Kennwort Bestätigen",
|
||||||
|
"account_settings": "Konto-Einstellungen",
|
||||||
|
"save": "Speichern",
|
||||||
|
"section_description": "Sie können Ihren Namen, Ihre E-Mail-Adresse und Ihr Passwort mit dem folgenden Formular aktualisieren.",
|
||||||
|
"updated_message": "Kontoeinstellungen erfolgreich aktualisiert"
|
||||||
|
},
|
||||||
|
"user_profile": {
|
||||||
|
"name": "Name",
|
||||||
|
"email": "E-Mail",
|
||||||
|
"password": "Passwort",
|
||||||
|
"confirm_password": "Kennwort bestätigen"
|
||||||
|
},
|
||||||
|
"notification": {
|
||||||
|
"title": "Benachrichtigung",
|
||||||
|
"email": "Benachrichtigungen senden an",
|
||||||
|
"description": "Welche E-Mail-Benachrichtigungen möchten Sie erhalten wenn sich etwas ändert?",
|
||||||
|
"invoice_viewed": "Rechnung angezeigt",
|
||||||
|
"invoice_viewed_desc": "Wenn Ihr Kunde die gesendete Rechnung anzeigt bekommt.",
|
||||||
|
"estimate_viewed": "Kostenvoranschlag angesehen",
|
||||||
|
"estimate_viewed_desc": "Wenn Ihr Kunde den gesendeten Kostenvoranschlag anzeigt bekommt.",
|
||||||
|
"save": "Speichern",
|
||||||
|
"email_save_message": "Email erfolgreich gespeichert",
|
||||||
|
"please_enter_email": "Bitte E-Mail eingeben"
|
||||||
|
},
|
||||||
|
"tax_types": {
|
||||||
|
"title": "Steuersätze",
|
||||||
|
"add_tax": "Steuersätze hinzufügen",
|
||||||
|
"description": "Sie können Steuern nach Belieben hinzufügen oder entfernen. Crater unterstützt Steuern auf einzelne Artikel sowie auf die Rechnung.",
|
||||||
|
"add_new_tax": "Neuen Steuersatz hinzufügen",
|
||||||
|
"tax_settings": "Einstellungen Steuersatz",
|
||||||
|
"tax_per_item": "Steuersatz pro Artikel",
|
||||||
|
"tax_name": "Name des Steuersatzes",
|
||||||
|
"compound_tax": "Compound Tax",
|
||||||
|
"percent": "Prozent",
|
||||||
|
"action": "Aktion",
|
||||||
|
"tax_setting_description": "Aktivieren Sie diese Option, wenn Sie den Steuersatz zu einzelnen Rechnungspositionen hinzufügen möchten. Standardmäßig wird der Steuersatz direkt zur Rechnung hinzugefügt.",
|
||||||
|
"created_message": "Steuersatz erfolgreich erstellt",
|
||||||
|
"updated_message": "Steuersatz erfolgreich aktualisiert",
|
||||||
|
"deleted_message": "Steuersatz erfolgreich gelöscht",
|
||||||
|
"confirm_delete": "Sie können diesen Steuersatz nicht wiederherstellen",
|
||||||
|
"already_in_use": "Steuersatz wird bereits verwendet"
|
||||||
|
},
|
||||||
|
"expense_category": {
|
||||||
|
"title": "Kategorien Kosten",
|
||||||
|
"action": "Aktion",
|
||||||
|
"description": "Für das Hinzufügen von Ausgabeneinträgen sind Kategorien erforderlich. Sie können diese Kategorien nach Ihren Wünschen hinzufügen oder entfernen.",
|
||||||
|
"add_new_category": "Neue Kategorie hinzufügen",
|
||||||
|
"category_name": "Kategorie Name",
|
||||||
|
"category_description": "Beschreibung",
|
||||||
|
"created_message": "Ausgabenkategorie erfolgreich erstellt",
|
||||||
|
"deleted_message": "Ausgabenkategorie erfolgreich gelöscht",
|
||||||
|
"updated_message": "Ausgabenkategorie erfolgreich aktualisiert",
|
||||||
|
"confirm_delete": "Sie können diese Ausgabenkategorie nicht wiederherstellen",
|
||||||
|
"already_in_use": "Kategorie wird bereits verwendet"
|
||||||
|
},
|
||||||
|
"preferences": {
|
||||||
|
"currency": "Währung",
|
||||||
|
"language": "Sprache",
|
||||||
|
"time_zone": "Zeitzone",
|
||||||
|
"fiscal_year": "Geschäftsjahr",
|
||||||
|
"date_format": "Datum-Format",
|
||||||
|
"discount_setting": "Einstellung Rabatt",
|
||||||
|
"discount_per_item": "Rabatt pro Artikel ",
|
||||||
|
"discount_setting_description": "Aktivieren Sie diese Option, wenn Sie einzelnen Rechnungspositionen einen Rabatt hinzufügen möchten. Standardmäßig wird der Rabatt direkt zur Rechnung hinzugefügt.",
|
||||||
|
"save": "Speichern",
|
||||||
|
"preference": "Präferenz | Präferenzen",
|
||||||
|
"general_settings": "Standardeinstellungen für das System.",
|
||||||
|
"updated_message": "Einstellungen erfolgreich aktualisiert",
|
||||||
|
"select_language": "Sprache auswählen",
|
||||||
|
"select_time_zone": "Zeitzone auswählen",
|
||||||
|
"select_date_formate": "select Date Formate",
|
||||||
|
"select_financial_year": "Geschäftsjahr auswählen"
|
||||||
|
},
|
||||||
|
"update_app": {
|
||||||
|
"title": "Applikation aktualisieren",
|
||||||
|
"description": "Sie können Crater ganz einfach aktualisieren, indem Sie auf die Schaltfläche unten klicken, um nach einem neuen Update zu suchen.",
|
||||||
|
"check_update": "Nach Updates suchen",
|
||||||
|
"avail_update": "Neues Update verfügbar",
|
||||||
|
"next_version": "Nächste Version",
|
||||||
|
"update": "Jetzt aktualisieren",
|
||||||
|
"update_progress": "Update läuft ...",
|
||||||
|
"progress_text": "Es dauert nur ein paar Minuten. Bitte aktualisieren Sie den Bildschirm nicht und schließen Sie das Fenster nicht, bevor das Update abgeschlossen ist.",
|
||||||
|
"update_success": "App wurde aktualisiert! Bitte warten Sie, während Ihr Browserfenster automatisch neu geladen wird.",
|
||||||
|
"latest_message": "Kein Update verfügbar! Du bist auf der neuesten Version.",
|
||||||
|
"current_version": "Aktuelle Version",
|
||||||
|
"download_zip_file": "Laden Sie die ZIP-Datei herunter",
|
||||||
|
"unzipping_package": "Paket entpacken",
|
||||||
|
"copying_files": "Dateien kopieren",
|
||||||
|
"running_migrations": "Ausführen von Migrationen",
|
||||||
|
"finishing_update": "Update beenden",
|
||||||
|
"update_failed": "Update fehlgeschlagen",
|
||||||
|
"update_failed_text": "Es tut uns leid! Ihr Update ist am folgenden Schritt fehlgeschlagen: {step}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wizard": {
|
||||||
|
"account_info": "Account-Informationen",
|
||||||
|
"account_info_desc": "Die folgenden Details werden zum Erstellen des Hauptadministratorkontos verwendet. Sie können die Details auch jederzeit nach dem Anmelden ändern.",
|
||||||
|
"name": "Name",
|
||||||
|
"email": "Email",
|
||||||
|
"password": "Passwort",
|
||||||
|
"confirm_password": "Passwort bestätigen",
|
||||||
|
"save_cont": "Speichern und weiter",
|
||||||
|
"company_info": "Unternehmensinformationen",
|
||||||
|
"company_info_desc": "Diese Informationen werden auf Rechnungen angezeigt. Beachten Sie, dass Sie diese später auf der Einstellungsseite bearbeiten können.",
|
||||||
|
"company_name": "Firmenname",
|
||||||
|
"company_logo": "Firmenlogo",
|
||||||
|
"logo_preview": "Vorschau Logo",
|
||||||
|
"preferences": "Einstellungen",
|
||||||
|
"preferences_desc": "Standardeinstellungen für das System.",
|
||||||
|
"country": "Land",
|
||||||
|
"state": "Bundesland",
|
||||||
|
"city": "Stadt",
|
||||||
|
"address": "Adresse",
|
||||||
|
"street": "Straße1 | Straße2",
|
||||||
|
"phone": "Telefon",
|
||||||
|
"zip_code": "Postleitzahl",
|
||||||
|
"go_back": "Zurück",
|
||||||
|
"currency": "Währung",
|
||||||
|
"language": "Sprache",
|
||||||
|
"time_zone": "Zeitzone",
|
||||||
|
"fiscal_year": "Geschäftsjahr",
|
||||||
|
"date_format": "Datumsformat",
|
||||||
|
"from_address": "From Address",
|
||||||
|
"username": "Benutzername",
|
||||||
|
"next": "Next",
|
||||||
|
"continue": "Weiter",
|
||||||
|
"skip": "Überspringen",
|
||||||
|
"database": {
|
||||||
|
"database": "URL der Seite & Datenbank",
|
||||||
|
"connection": "Datenbank Verbindung",
|
||||||
|
"host": "Datenbank Host",
|
||||||
|
"port": "Datenbank Port",
|
||||||
|
"password": "Datenbank Passwort",
|
||||||
|
"app_url": "App-URL",
|
||||||
|
"username": "Datenbank Benutzername",
|
||||||
|
"db_name": "Datenbank Name",
|
||||||
|
"desc": "Erstellen Sie eine Datenbank auf Ihrem Server und legen Sie die Anmeldeinformationen mithilfe des folgenden Formulars fest."
|
||||||
|
},
|
||||||
|
"permissions": {
|
||||||
|
"permissions": "Berechtigungen",
|
||||||
|
"permission_confirm_title": "Sind Sie sicher, dass Sie fortfahren möchten?",
|
||||||
|
"permission_confirm_desc": "Prüfung der Berechtigung der Ordner fehlgeschlagen.",
|
||||||
|
"permission_desc": "Unten finden Sie eine Liste der Ordnerberechtigungen, die erforderlich sind, damit die App funktioniert. Wenn die Berechtigungsprüfung fehlschlägt, müssen Sie Ihre Ordnerberechtigungen aktualisieren."
|
||||||
|
},
|
||||||
|
"mail": {
|
||||||
|
"host": "E-Mail-Host",
|
||||||
|
"port": "E-Mail-Port",
|
||||||
|
"driver": "E-Mail-Treiber",
|
||||||
|
"secret": "Verschlüsselung",
|
||||||
|
"mailgun_secret": "Mailgun Verschlüsselung",
|
||||||
|
"mailgun_domain": "Domain",
|
||||||
|
"mailgun_endpoint": "Mailgun-Endpunkt",
|
||||||
|
"ses_secret": "SES Verschlüsselung",
|
||||||
|
"ses_key": "SES-Taste",
|
||||||
|
"password": "E-Mail-Passwort",
|
||||||
|
"username": "E-Mail-Benutzername",
|
||||||
|
"mail_config": "E-Mail-Konfiguration",
|
||||||
|
"from_name": "Von E-Mail-Absendername",
|
||||||
|
"from_mail": "Von E-Mail-Absenderadresse",
|
||||||
|
"encryption": "E-Mail-Verschlüsselung",
|
||||||
|
"mail_config_desc": "Unten finden Sie das Formular zum Konfigurieren des E-Mail-Treibers zum Senden von E-Mails über die App. Sie können auch Drittanbieter wie Sendgrid, SES usw. konfigurieren."
|
||||||
|
},
|
||||||
|
"req": {
|
||||||
|
"system_req": "System Anforderungen",
|
||||||
|
"php_req_version": "Php (version {version} erforderlich)",
|
||||||
|
"check_req": "Anforderungen prüfen",
|
||||||
|
"system_req_desc": "Crater hat einige Serveranforderungen. Stellen Sie sicher, dass Ihr Server die erforderliche PHP-Version und alle unten genannten Erweiterungen hat."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"migrate_failed": "Migration ist Fehlgeschlagen",
|
||||||
|
"database_variables_save_error": "Konfiguration kann nicht in EN.env-Datei geschrieben werden. Bitte überprüfen Sie die Dateiberechtigungen.",
|
||||||
|
"mail_variables_save_error": "E-Mail-Konfiguration fehlgeschlagen.",
|
||||||
|
"connection_failed": "Datenbankverbindung fehlgeschlagen",
|
||||||
|
"database_should_be_empty": "Datenbank sollte leer sein"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"mail_variables_save_successfully": "E-Mail erfolgreich konfiguriert",
|
||||||
|
"database_variables_save_successfully": "Datenbank erfolgreich konfiguriert."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"layout_login": {
|
||||||
|
"copyright_crater": "Copyright @ Crater - 2020",
|
||||||
|
"super_simple_invoicing": "Super einfache Buchhaltung",
|
||||||
|
"for_freelancer": "für Freelancers &",
|
||||||
|
"small_businesses": "kleine Unternehmen",
|
||||||
|
"crater_help": "Crater hilft dir eine wunderschönen Überblick über deine Buchhaltung zuhaben.",
|
||||||
|
"invoices_and_estimates": "Die Möglichkeit mehrere Versionen von Rechnungen und Kosten zuerstellen."
|
||||||
|
},
|
||||||
|
"validation": {
|
||||||
|
"invalid_url": "Ungültige URL (Bsp.: http://www.crater.com)",
|
||||||
|
"required": "Feld ist erforderlich",
|
||||||
|
"email_incorrect": "Falsche E-Mail.",
|
||||||
|
"email_already_taken": "Die E-Mail ist bereits vergeben.",
|
||||||
|
"email_does_not_exist": "Benutzer mit der angegebenen E-Mail existiert nicht",
|
||||||
|
"item_unit_already_taken": "Die Artikeleinheit wurde bereits vergeben",
|
||||||
|
"payment_mode_already_taken": "Der Zahlungsmodus wurde bereits verwendet",
|
||||||
|
"send_reset_link": "Link zum Zurücksetzen senden",
|
||||||
|
"not_yet": "Noch erhalten? Erneut senden",
|
||||||
|
"password_min_length": "Password muß {count} Zeichen enthalten",
|
||||||
|
"name_min_length": "Name muss mindestens {count} Zeichen enthalten.",
|
||||||
|
"enter_valid_tax_rate": "Geben Sie einen gültige Steuersatz ein",
|
||||||
|
"numbers_only": "Nur Zahlen.",
|
||||||
|
"characters_only": "Nur Zeichen.",
|
||||||
|
"password_incorrect": "Passwörter müssen identisch sein",
|
||||||
|
"password_length": "Passwort muss {count} Zeichen lang sein.",
|
||||||
|
"qty_must_greater_than_zero": "Die Menge muss größer als 0 sein.",
|
||||||
|
"price_greater_than_zero": "Preis muss größer als 0 sein.",
|
||||||
|
"payment_greater_than_zero": "Die Zahlung muss größer als 0 sein.",
|
||||||
|
"payment_greater_than_due_amount": "Die eingegebene Zahlung ist mehr als der fällige Betrag dieser Rechnung.",
|
||||||
|
"quantity_maxlength": "Die Menge sollte nicht größer als 20 Ziffern sein.",
|
||||||
|
"price_maxlength": "Der Preis sollte nicht größer als 20 Ziffern sein.",
|
||||||
|
"price_minvalue": "Der Preis sollte größer als 0 sein.",
|
||||||
|
"amount_maxlength": "Der Betrag sollte nicht größer als 20 Ziffern sein.",
|
||||||
|
"amount_minvalue": "Betrag sollte größer als 0 sein.",
|
||||||
|
"description_maxlength": "Die Beschreibung sollte nicht länger als 255 Zeichen sein.",
|
||||||
|
"subject_maxlength": "Der Betreff sollte nicht länger als 100 Zeichen sein.",
|
||||||
|
"message_maxlength": "Die Nachricht sollte nicht länger als 255 Zeichen sein.",
|
||||||
|
"maximum_options_error": "Maximal {max} Optionen ausgewählt. Entfernen Sie zuerst eine ausgewählte Option, um eine andere auszuwählen.",
|
||||||
|
"notes_maxlength": "Notizen sollten nicht länger als 255 Zeichen sein.",
|
||||||
|
"address_maxlength": "Die Adresse sollte nicht länger als 255 Zeichen sein.",
|
||||||
|
"ref_number_maxlength": "Ref Number sollte nicht länger als 255 Zeichen sein.",
|
||||||
|
"prefix_maxlength": "Das Präfix sollte nicht länger als 5 Zeichen sein.",
|
||||||
|
"something_went_wrong": "Etwas ist falsch gelaufen"
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user