mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-28 04:01:10 -04:00
Compare commits
212 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 06a538bb81 | |||
| 7ab0419f27 | |||
| a7275aaa42 | |||
| bc4e6a05ea | |||
| ca170f5a87 | |||
| 22e7e96dfa | |||
| fcfd1ddb7a | |||
| daf8c9265b | |||
| 824d2e3e8d | |||
| 3cd975dbbd | |||
| 8e50c36a71 | |||
| b499741ab4 | |||
| b409cdb913 | |||
| 13e56105e3 | |||
| da996c1f33 | |||
| bb6fb2f49d | |||
| 400296575e | |||
| d58c790b1f | |||
| c674c2ab9e | |||
| d79692cf3b | |||
| 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 | |||
| 7bba576dca | |||
| 05454af593 | |||
| 74fe481ed5 | |||
| 1cd654b0cc | |||
| f4a4c05b61 | |||
| 24637bff4a | |||
| 887ad9a73d | |||
| 339099bd34 | |||
| 9b9761aa5a | |||
| 0c71356f59 | |||
| e539bb501d | |||
| 2fcd169270 | |||
| 00c917853c | |||
| 122c4f478f | |||
| edc0e115e4 | |||
| b388e7a237 | |||
| 6e3ed9b4f6 | |||
| 338dbb26a1 | |||
| f10e5e9d11 | |||
| 3a046b638c | |||
| 36242c516a | |||
| 14d71fedb3 | |||
| c8843eb544 | |||
| 7fe9a4c2a2 | |||
| 37f2b6dfc7 | |||
| c90c14312a | |||
| b5b861bb36 | |||
| ab041743a2 | |||
| 9bcec9bd75 | |||
| 7b697a477e | |||
| 146cf835b9 | |||
| ec87e72547 | |||
| bf2e8c9c99 | |||
| b6096aadfa | |||
| 1cbc41c3ce | |||
| f4ca6d4b73 | |||
| 66649590e5 | |||
| 1e8cc475ca | |||
| 98d76a2f92 | |||
| 7b50148c43 | |||
| aef6da8b7b | |||
| 0fb14afc08 | |||
| dad71b04dd | |||
| 80014b02b5 | |||
| 7c2a6700eb | |||
| 7e81013b15 | |||
| f0107129fb | |||
| 04cce64859 | |||
| 3b7637f3cf | |||
| 7333746948 | |||
| 0fa6049298 | |||
| 64be6ce957 | |||
| 0e075c03d8 | |||
| 5de195b56b | |||
| cd60f1b096 | |||
| 8058f9b022 | |||
| a484506029 | |||
| a69f99dc61 | |||
| c3583c98be | |||
| 813e574425 | |||
| ac431ca815 | |||
| dbc5950294 | |||
| 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_KEY=base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0=
|
||||
APP_DEBUG=false
|
||||
APP_DEBUG=true
|
||||
APP_LOG_LEVEL=debug
|
||||
APP_URL=http://crater.test
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_HOST=db
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=crater
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=bytefury
|
||||
DB_USERNAME=crater
|
||||
DB_PASSWORD="crater"
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
|
||||
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
|
||||
/.expo
|
||||
/.vscode
|
||||
docker-compose.yml
|
||||
docker-compose.yaml
|
||||
|
||||
52
Dockerfile
Normal file
52
Dockerfile
Normal file
@ -0,0 +1,52 @@
|
||||
##### 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 && \
|
||||
docker-php-ext-install bcmath ctype json gd mbstring pdo pdo_mysql tokenizer xml zip
|
||||
|
||||
# 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"]
|
||||
|
||||
@ -4,20 +4,18 @@ namespace Crater;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Crater\User;
|
||||
use Crater\Country;
|
||||
use Crater\State;
|
||||
use Crater\City;
|
||||
|
||||
class Address extends Model
|
||||
{
|
||||
const BILLING_TYPE = 'BILLING';
|
||||
const SHIPPING_TYPE = 'SHIPPING';
|
||||
const BILLING_TYPE = 'billing';
|
||||
const SHIPPING_TYPE = 'shipping';
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'address_street_1',
|
||||
'address_street_2',
|
||||
'city_id',
|
||||
'state_id',
|
||||
'city',
|
||||
'state',
|
||||
'country_id',
|
||||
'zip',
|
||||
'phone',
|
||||
@ -35,14 +33,4 @@ class Address extends Model
|
||||
{
|
||||
return $this->belongsTo(Country::class);
|
||||
}
|
||||
|
||||
public function state()
|
||||
{
|
||||
return $this->belongsTo(State::class);
|
||||
}
|
||||
|
||||
public function city()
|
||||
{
|
||||
return $this->belongsTo(City::class);
|
||||
}
|
||||
}
|
||||
|
||||
18
app/City.php
18
app/City.php
@ -1,18 +0,0 @@
|
||||
<?php
|
||||
namespace Crater;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Crater\State;
|
||||
|
||||
class City extends Model
|
||||
{
|
||||
public function state()
|
||||
{
|
||||
return $this->belongsTo(State::class);
|
||||
}
|
||||
|
||||
public function address()
|
||||
{
|
||||
return $this->hasMany(Address::class);
|
||||
}
|
||||
}
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,7 @@ class Kernel extends ConsoleKernel
|
||||
* @var array
|
||||
*/
|
||||
protected $commands = [
|
||||
|
||||
Commands\ResetApp::class
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@ -2,15 +2,9 @@
|
||||
namespace Crater;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Crater\State;
|
||||
|
||||
class Country extends Model
|
||||
{
|
||||
public function states()
|
||||
{
|
||||
return $this->hasMany(State::class);
|
||||
}
|
||||
|
||||
public function address()
|
||||
{
|
||||
return $this->hasMany(Address::class);
|
||||
|
||||
@ -49,15 +49,20 @@ class Estimate extends Model
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'total' => 'float',
|
||||
'tax' => 'float',
|
||||
'sub_total' => 'float'
|
||||
'total' => 'integer',
|
||||
'tax' => 'integer',
|
||||
'sub_total' => 'integer',
|
||||
'discount' => 'float',
|
||||
'discount_val' => 'integer',
|
||||
];
|
||||
|
||||
public static function getNextEstimateNumber()
|
||||
public static function getNextEstimateNumber($value)
|
||||
{
|
||||
// Get the last created order
|
||||
$lastOrder = Estimate::orderBy('created_at', 'desc')->first();
|
||||
// Get the last created order
|
||||
$lastOrder = Estimate::where('estimate_number', 'LIKE', $value . '-%')
|
||||
->orderBy('created_at', 'desc')
|
||||
->first();
|
||||
|
||||
if (!$lastOrder) {
|
||||
// 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.
|
||||
@ -99,10 +104,16 @@ class Estimate extends Model
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public function getEstimatePrefixAttribute()
|
||||
{
|
||||
$prefix = explode("-",$this->estimate_number)[0];
|
||||
return $prefix;
|
||||
}
|
||||
|
||||
private function strposX($haystack, $needle, $number)
|
||||
{
|
||||
if ($number == '1') {
|
||||
|
||||
@ -24,6 +24,7 @@ class EstimateItem extends Model
|
||||
'price' => 'integer',
|
||||
'total' => 'integer',
|
||||
'discount' => 'float',
|
||||
'quantity' => 'float',
|
||||
'discount_val' => 'integer',
|
||||
'tax' => 'integer'
|
||||
];
|
||||
|
||||
@ -20,11 +20,22 @@ use Crater\CompanySetting;
|
||||
|
||||
class CompanyController extends Controller
|
||||
{
|
||||
/**
|
||||
* Retrive the Admin account.
|
||||
* @return \Crater\User
|
||||
*/
|
||||
public function getAdmin()
|
||||
{
|
||||
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)
|
||||
{
|
||||
$verifyEmail = User::where('email', $request->email)->first();
|
||||
@ -54,15 +65,30 @@ 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()
|
||||
{
|
||||
$user = User::with(['addresses', 'addresses.country', 'addresses.state', 'addresses.city', 'company'])->find(1);
|
||||
$user = User::with(['addresses', 'addresses.country', 'company'])->find(1);
|
||||
|
||||
return response()->json([
|
||||
'user' => $user
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update Admin Company Details
|
||||
* @param \Crater\Http\Requests\CompanyRequest $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function updateAdminCompany(CompanyRequest $request)
|
||||
{
|
||||
$user = User::find(1);
|
||||
@ -75,9 +101,9 @@ class CompanyController extends Controller
|
||||
$company->addMediaFromRequest('logo')->toMediaCollection('logo');
|
||||
}
|
||||
|
||||
$fields = $request->only(['address_street_1', 'address_street_2', 'city_id', 'state_id', 'country_id', 'zip', 'phone']);
|
||||
$fields = $request->only(['address_street_1', 'address_street_2', 'city', 'state', 'country_id', 'zip', 'phone']);
|
||||
$address = Address::updateOrCreate(['user_id' => 1], $fields);
|
||||
$user = User::with(['addresses', 'addresses.country', 'addresses.state', 'addresses.city', 'company'])->find(1);
|
||||
$user = User::with(['addresses', 'addresses.country', 'company'])->find(1);
|
||||
|
||||
return response()->json([
|
||||
'user' => $user,
|
||||
@ -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)
|
||||
{
|
||||
$date_formats = DateFormatter::get_list();
|
||||
@ -115,7 +146,10 @@ class CompanyController extends Controller
|
||||
$languages = [
|
||||
["code"=>"en", "name" => "English"],
|
||||
["code"=>"fr", "name" => "French"],
|
||||
["code"=>"es", "name" => "Spanish"]
|
||||
["code"=>"es", "name" => "Spanish"],
|
||||
["code"=>"ar", "name" => "العربية"],
|
||||
["code"=>"de", "name" => "German"],
|
||||
["code"=>"pt_BR", "name" => "Brazilian Portuguese"],
|
||||
];
|
||||
|
||||
return response()->json([
|
||||
@ -133,6 +167,13 @@ class CompanyController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update General App Settings
|
||||
* @param \Crater\Http\Requests\CompanySettingRequest $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function updateGeneralSettings(CompanySettingRequest $request)
|
||||
{
|
||||
$sets = [
|
||||
@ -153,6 +194,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)
|
||||
{
|
||||
CompanySetting::setSetting($request->key, $request->value, $request->header('company'));
|
||||
@ -162,6 +260,11 @@ class CompanyController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve Specific Company Setting
|
||||
* @param \Crater\Http\Requests\SettingKeyRequest $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getSetting(SettingKeyRequest $request)
|
||||
{
|
||||
$setting = CompanySetting::getSetting($request->key, $request->header('company'));
|
||||
@ -171,6 +274,12 @@ class CompanyController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve App Colors
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getColors(Request $request)
|
||||
{
|
||||
$colors = [
|
||||
@ -205,7 +314,7 @@ class CompanyController extends Controller
|
||||
* Upload the company logo to storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function uploadCompanyLogo(Request $request)
|
||||
{
|
||||
@ -232,7 +341,7 @@ class CompanyController extends Controller
|
||||
* Upload the Admin Avatar to public storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function uploadAdminAvatar(Request $request)
|
||||
{
|
||||
|
||||
@ -19,7 +19,7 @@ class CustomersController extends Controller
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
@ -53,7 +53,7 @@ class CustomersController extends Controller
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(Requests\CustomerRequest $request)
|
||||
{
|
||||
@ -80,8 +80,8 @@ class CustomersController extends Controller
|
||||
$newAddress->name = $address["name"];
|
||||
$newAddress->address_street_1 = $address["address_street_1"];
|
||||
$newAddress->address_street_2 = $address["address_street_2"];
|
||||
$newAddress->city_id = $address["city_id"];
|
||||
$newAddress->state_id = $address["state_id"];
|
||||
$newAddress->city = $address["city"];
|
||||
$newAddress->state = $address["state"];
|
||||
$newAddress->country_id = $address["country_id"];
|
||||
$newAddress->zip = $address["zip"];
|
||||
$newAddress->phone = $address["phone"];
|
||||
@ -104,7 +104,7 @@ class CustomersController extends Controller
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
@ -112,11 +112,7 @@ class CustomersController extends Controller
|
||||
'billingAddress',
|
||||
'shippingAddress',
|
||||
'billingAddress.country',
|
||||
'billingAddress.state',
|
||||
'billingAddress.city',
|
||||
'shippingAddress.country',
|
||||
'shippingAddress.state',
|
||||
'shippingAddress.city',
|
||||
])->find($id);
|
||||
|
||||
return response()->json([
|
||||
@ -128,7 +124,7 @@ class CustomersController extends Controller
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
@ -148,7 +144,7 @@ class CustomersController extends Controller
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update($id, Requests\CustomerRequest $request)
|
||||
{
|
||||
@ -181,14 +177,15 @@ class CustomersController extends Controller
|
||||
$customer->enable_portal = $request->enable_portal;
|
||||
$customer->save();
|
||||
|
||||
$customer->addresses()->delete();
|
||||
if ($request->addresses) {
|
||||
foreach ($request->addresses as $address) {
|
||||
$newAddress = $customer->addresses()->firstOrNew(['type' => $address["type"]]);
|
||||
$newAddress->name = $address["name"];
|
||||
$newAddress->address_street_1 = $address["address_street_1"];
|
||||
$newAddress->address_street_2 = $address["address_street_2"];
|
||||
$newAddress->city_id = $address["city_id"];
|
||||
$newAddress->state_id = $address["state_id"];
|
||||
$newAddress->city = $address["city"];
|
||||
$newAddress->state = $address["state"];
|
||||
$newAddress->country_id = $address["country_id"];
|
||||
$newAddress->zip = $address["zip"];
|
||||
$newAddress->phone = $address["phone"];
|
||||
@ -207,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
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
@ -221,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)
|
||||
{
|
||||
foreach ($request->id as $id) {
|
||||
|
||||
@ -15,6 +15,12 @@ use Illuminate\Support\Facades\DB;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Retrieve Dashboard details
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$invoiceTotals = [];
|
||||
@ -30,7 +36,8 @@ class DashboardController extends Controller
|
||||
$start = Carbon::now();
|
||||
$end = Carbon::now();
|
||||
$terms = explode('-', $fiscalYear);
|
||||
if ($terms[0] < $start->month) {
|
||||
|
||||
if ($terms[0] <= $start->month) {
|
||||
$startDate->month($terms[0])->startOfMonth();
|
||||
$start->month($terms[0])->startOfMonth();
|
||||
$end->month($terms[0])->endOfMonth();
|
||||
@ -87,6 +94,7 @@ class DashboardController extends Controller
|
||||
}
|
||||
|
||||
$start->subMonth()->endOfMonth();
|
||||
|
||||
$salesTotal = Invoice::whereCompany($request->header('company'))
|
||||
->whereBetween(
|
||||
'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)
|
||||
{
|
||||
$expensesCategories = Expense::with('category')
|
||||
|
||||
@ -33,10 +33,14 @@ class EnvironmentController extends Controller
|
||||
*/
|
||||
public function saveDatabaseEnvironment(DatabaseEnvironmentRequest $request)
|
||||
{
|
||||
Artisan::call('config:clear');
|
||||
Artisan::call('cache:clear');
|
||||
|
||||
$results = $this->EnvironmentManager->saveDatabaseVariables($request);
|
||||
|
||||
if(array_key_exists("success", $results)) {
|
||||
Artisan::call('config:clear');
|
||||
Artisan::call('cache:clear');
|
||||
Artisan::call('storage:link');
|
||||
Artisan::call('key:generate --force');
|
||||
Artisan::call('migrate --seed --force');
|
||||
|
||||
@ -56,25 +56,43 @@ class EstimatesController extends Controller
|
||||
|
||||
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'));
|
||||
$discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company'));
|
||||
$customers = User::where('role', 'customer')->get();
|
||||
|
||||
return response()->json([
|
||||
'customers' => $customers,
|
||||
'nextEstimateNumber' => $nextEstimateNumber,
|
||||
'nextEstimateNumberAttribute' => $nextEstimateNumberAttribute,
|
||||
'nextEstimateNumber' => $estimate_prefix.'-'.$nextEstimateNumber,
|
||||
'taxes' => Tax::whereCompany($request->header('company'))->latest()->get(),
|
||||
'items' => Item::whereCompany($request->header('company'))->get(),
|
||||
'tax_per_item' => $tax_per_item,
|
||||
'discount_per_item' => $discount_per_item,
|
||||
'estimateTemplates' => EstimateTemplate::all(),
|
||||
'shareable_link' => ''
|
||||
'shareable_link' => '',
|
||||
'estimate_prefix' => $estimate_prefix
|
||||
]);
|
||||
}
|
||||
|
||||
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);
|
||||
$expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date);
|
||||
$status = Estimate::STATUS_DRAFT;
|
||||
@ -101,7 +119,7 @@ class EstimatesController extends Controller
|
||||
$estimate = Estimate::create([
|
||||
'estimate_date' => $estimate_date,
|
||||
'expiry_date' => $expiry_date,
|
||||
'estimate_number' => $request->estimate_number,
|
||||
'estimate_number' => $number_attributes['estimate_number'],
|
||||
'reference_number' => $request->reference_number,
|
||||
'user_id' => $request->user_id,
|
||||
'company_id' => $request->header('company'),
|
||||
@ -127,7 +145,7 @@ class EstimatesController extends Controller
|
||||
|
||||
if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) {
|
||||
foreach ($estimateItem['taxes'] as $tax) {
|
||||
if ($tax['amount']) {
|
||||
if (gettype($tax['amount']) !== "NULL") {
|
||||
$tax['company_id'] = $request->header('company');
|
||||
$item->taxes()->create($tax);
|
||||
}
|
||||
@ -137,7 +155,7 @@ class EstimatesController extends Controller
|
||||
|
||||
if ($request->has('taxes')) {
|
||||
foreach ($request->taxes as $tax) {
|
||||
if ($tax['amount']) {
|
||||
if (gettype($tax['amount']) !== "NULL") {
|
||||
$tax['company_id'] = $request->header('company');
|
||||
$estimate->taxes()->create($tax);
|
||||
}
|
||||
@ -150,10 +168,6 @@ class EstimatesController extends Controller
|
||||
$data['user'] = User::find($userId)->toArray();
|
||||
$data['company'] = Company::find($estimate->company_id);
|
||||
$email = $data['user']['email'];
|
||||
$notificationEmail = CompanySetting::getSetting(
|
||||
'notification_email',
|
||||
$request->header('company')
|
||||
);
|
||||
|
||||
if (!$email) {
|
||||
return response()->json([
|
||||
@ -161,13 +175,13 @@ class EstimatesController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
if (!$notificationEmail) {
|
||||
if (!config('mail.from.name')) {
|
||||
return response()->json([
|
||||
'error' => 'notification_email_does_not_exist'
|
||||
'error' => 'from_email_does_not_exist'
|
||||
]);
|
||||
}
|
||||
|
||||
\Mail::to($email)->send(new EstimatePdf($data, $notificationEmail));
|
||||
\Mail::to($email)->send(new EstimatePdf($data));
|
||||
}
|
||||
|
||||
$estimate = Estimate::with([
|
||||
@ -216,26 +230,33 @@ class EstimatesController extends Controller
|
||||
|
||||
return response()->json( [
|
||||
'customers' => $customers,
|
||||
'nextEstimateNumber' => $estimate->estimate_number,
|
||||
'nextEstimateNumber' => $estimate->getEstimateNumAttribute(),
|
||||
'taxes' => Tax::latest()->whereCompany($request->header('company'))->get(),
|
||||
'estimate' => $estimate,
|
||||
'items' => Item::whereCompany($request->header('company'))->latest()->get(),
|
||||
'estimateTemplates' => EstimateTemplate::all(),
|
||||
'tax_per_item' => $estimate->tax_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)
|
||||
{
|
||||
$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);
|
||||
$expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date);
|
||||
|
||||
$estimate = Estimate::find($id);
|
||||
$estimate->estimate_date = $estimate_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->user_id = $request->user_id;
|
||||
$estimate->estimate_template_id = $request->estimate_template_id;
|
||||
@ -266,7 +287,7 @@ class EstimatesController extends Controller
|
||||
|
||||
if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) {
|
||||
foreach ($estimateItem['taxes'] as $tax) {
|
||||
if ($tax['amount']) {
|
||||
if (gettype($tax['amount']) !== "NULL") {
|
||||
$tax['company_id'] = $request->header('company');
|
||||
$item->taxes()->create($tax);
|
||||
}
|
||||
@ -276,7 +297,7 @@ class EstimatesController extends Controller
|
||||
|
||||
if ($request->has('taxes')) {
|
||||
foreach ($request->taxes as $tax) {
|
||||
if ($tax['amount']) {
|
||||
if (gettype($tax['amount']) !== "NULL") {
|
||||
$tax['company_id'] = $request->header('company');
|
||||
$estimate->taxes()->create($tax);
|
||||
}
|
||||
@ -315,10 +336,6 @@ class EstimatesController extends Controller
|
||||
$data['company'] = Company::find($estimate->company_id);
|
||||
|
||||
$email = $data['user']['email'];
|
||||
$notificationEmail = CompanySetting::getSetting(
|
||||
'notification_email',
|
||||
$request->header('company')
|
||||
);
|
||||
|
||||
if (!$email) {
|
||||
return response()->json([
|
||||
@ -326,13 +343,13 @@ class EstimatesController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
if (!$notificationEmail) {
|
||||
if (!config('mail.from.name')) {
|
||||
return response()->json([
|
||||
'error' => 'notification_email_does_not_exist'
|
||||
'error' => 'from_email_does_not_exist'
|
||||
]);
|
||||
}
|
||||
|
||||
\Mail::to($email)->send(new EstimatePdf($data, $notificationEmail));
|
||||
\Mail::to($email)->send(new EstimatePdf($data));
|
||||
|
||||
if ($estimate->status == Estimate::STATUS_DRAFT) {
|
||||
$estimate->status = Estimate::STATUS_SENT;
|
||||
@ -381,6 +398,10 @@ class EstimatesController extends Controller
|
||||
{
|
||||
$estimate = Estimate::with(['items', 'items.taxes', 'user', 'estimateTemplate', 'taxes'])->find($id);
|
||||
$invoice_date = Carbon::parse($estimate->estimate_date);
|
||||
$invoice_prefix = CompanySetting::getSetting(
|
||||
'invoice_prefix',
|
||||
$request->header('company')
|
||||
);
|
||||
$due_date = Carbon::parse($estimate->estimate_date)->addDays(7);
|
||||
$tax_per_item = CompanySetting::getSetting(
|
||||
'tax_per_item',
|
||||
@ -400,7 +421,7 @@ class EstimatesController extends Controller
|
||||
$invoice = Invoice::create([
|
||||
'invoice_date' => $invoice_date,
|
||||
'due_date' => $due_date,
|
||||
'invoice_number' => "INV-".Invoice::getNextInvoiceNumber(),
|
||||
'invoice_number' => $invoice_prefix."-".Invoice::getNextInvoiceNumber($invoice_prefix),
|
||||
'reference_number' => $estimate->reference_number,
|
||||
'user_id' => $estimate->user_id,
|
||||
'company_id' => $request->header('company'),
|
||||
|
||||
@ -17,7 +17,7 @@ class ExpensesController extends Controller
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
@ -48,7 +48,7 @@ class ExpensesController extends Controller
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function create(Request $request)
|
||||
{
|
||||
@ -63,7 +63,7 @@ class ExpensesController extends Controller
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function store(ExpenseRequest $request)
|
||||
{
|
||||
@ -91,7 +91,7 @@ class ExpensesController extends Controller
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Crater\Expense $expense
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Expense $expense)
|
||||
{
|
||||
@ -102,7 +102,7 @@ class ExpensesController extends Controller
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function edit(Request $request,$id)
|
||||
{
|
||||
@ -122,7 +122,7 @@ class ExpensesController extends Controller
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Crater\Expense $expense
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function update(ExpenseRequest $request, Expense $expense)
|
||||
{
|
||||
@ -150,7 +150,7 @@ class ExpensesController extends Controller
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \Crater\Expense $expense
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy(Expense $expense)
|
||||
{
|
||||
@ -175,7 +175,7 @@ class ExpensesController extends Controller
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function uploadReceipts(Request $request, $id)
|
||||
{
|
||||
@ -200,6 +200,12 @@ class ExpensesController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrive details of an expense receipt from storage.
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function showReceipt($id)
|
||||
{
|
||||
$expense = Expense::find($id);
|
||||
@ -226,6 +232,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)
|
||||
{
|
||||
$company = Company::where('unique_hash', $hash)->first();
|
||||
|
||||
@ -6,6 +6,7 @@ use Crater\Invoice;
|
||||
use PDF;
|
||||
use Crater\CompanySetting;
|
||||
use Crater\Estimate;
|
||||
use Crater\Payment;
|
||||
use Crater\User;
|
||||
use Crater\Company;
|
||||
use Crater\InvoiceTemplate;
|
||||
@ -90,7 +91,7 @@ class FrontendController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
$companyAddress = User::with(['addresses', 'addresses.country', 'addresses.state', 'addresses.city'])->find(1);
|
||||
$companyAddress = User::with(['addresses', 'addresses.country'])->find(1);
|
||||
|
||||
$colors = [
|
||||
'invoice_primary_color',
|
||||
@ -118,6 +119,11 @@ class FrontendController extends Controller
|
||||
return $pdf->stream();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function getCustomerInvoicePdf($id)
|
||||
{
|
||||
$invoice = Invoice::with([
|
||||
@ -189,7 +195,7 @@ class FrontendController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
$companyAddress = User::with(['addresses', 'addresses.country', 'addresses.state', 'addresses.city'])->find(1);
|
||||
$companyAddress = User::with(['addresses', 'addresses.country'])->find(1);
|
||||
|
||||
$colors = [
|
||||
'invoice_primary_color',
|
||||
@ -262,7 +268,7 @@ class FrontendController extends Controller
|
||||
$estimateTemplate = EstimateTemplate::find($estimate->estimate_template_id);
|
||||
|
||||
$company = Company::find($estimate->company_id);
|
||||
$companyAddress = User::with(['addresses', 'addresses.country', 'addresses.state', 'addresses.city'])->find(1);
|
||||
$companyAddress = User::with(['addresses', 'addresses.country'])->find(1);
|
||||
$logo = $company->getMedia('logo')->first();
|
||||
|
||||
if($logo) {
|
||||
@ -338,7 +344,7 @@ class FrontendController extends Controller
|
||||
|
||||
$invoiceTemplate = InvoiceTemplate::find($invoice->invoice_template_id);
|
||||
$company = Company::find($invoice->company_id);
|
||||
$companyAddress = User::with(['addresses', 'addresses.country', 'addresses.state', 'addresses.city'])->find(1);
|
||||
$companyAddress = User::with(['addresses', 'addresses.country'])->find(1);
|
||||
|
||||
$logo = $company->getMedia('logo')->first();
|
||||
|
||||
@ -371,4 +377,34 @@ class FrontendController extends Controller
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ class InvoicesController extends Controller
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
@ -60,20 +60,30 @@ class InvoicesController extends Controller
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function create(Request $request)
|
||||
{
|
||||
$tax_per_item = CompanySetting::getSetting('tax_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([
|
||||
'nextInvoiceNumber' => $nextInvoiceNumber,
|
||||
'nextInvoiceNumberAttribute' => $nextInvoiceNumberAttribute,
|
||||
'nextInvoiceNumber' => $invoice_prefix.'-'.$nextInvoiceNumber,
|
||||
'items' => Item::with('taxes')->whereCompany($request->header('company'))->get(),
|
||||
'invoiceTemplates' => InvoiceTemplate::all(),
|
||||
'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.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
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);
|
||||
$due_date = Carbon::createFromFormat('d/m/Y', $request->due_date);
|
||||
$status = Invoice::STATUS_DRAFT;
|
||||
@ -99,7 +116,7 @@ class InvoicesController extends Controller
|
||||
$invoice = Invoice::create([
|
||||
'invoice_date' => $invoice_date,
|
||||
'due_date' => $due_date,
|
||||
'invoice_number' => $request->invoice_number,
|
||||
'invoice_number' => $number_attributes['invoice_number'],
|
||||
'reference_number' => $request->reference_number,
|
||||
'user_id' => $request->user_id,
|
||||
'company_id' => $request->header('company'),
|
||||
@ -128,8 +145,7 @@ class InvoicesController extends Controller
|
||||
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
|
||||
foreach ($invoiceItem['taxes'] as $tax) {
|
||||
$tax['company_id'] = $request->header('company');
|
||||
|
||||
if ($tax['amount']) {
|
||||
if (gettype($tax['amount']) !== "NULL") {
|
||||
$item->taxes()->create($tax);
|
||||
}
|
||||
}
|
||||
@ -140,7 +156,7 @@ class InvoicesController extends Controller
|
||||
foreach ($request->taxes as $tax) {
|
||||
$tax['company_id'] = $request->header('company');
|
||||
|
||||
if ($tax['amount']) {
|
||||
if (gettype($tax['amount']) !== "NULL") {
|
||||
$invoice->taxes()->create($tax);
|
||||
}
|
||||
}
|
||||
@ -151,11 +167,6 @@ class InvoicesController extends Controller
|
||||
$data['user'] = User::find($request->user_id)->toArray();
|
||||
$data['company'] = Company::find($invoice->company_id);
|
||||
|
||||
$notificationEmail = CompanySetting::getSetting(
|
||||
'notification_email',
|
||||
$request->header('company')
|
||||
);
|
||||
|
||||
$email = $data['user']['email'];
|
||||
|
||||
if (!$email) {
|
||||
@ -164,13 +175,13 @@ class InvoicesController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
if (!$notificationEmail) {
|
||||
if (!config('mail.from.name')) {
|
||||
return response()->json([
|
||||
'error' => 'notification_email_does_not_exist'
|
||||
'error' => 'from_email_does_not_exist'
|
||||
]);
|
||||
}
|
||||
|
||||
\Mail::to($email)->send(new invoicePdf($data, $notificationEmail));
|
||||
\Mail::to($email)->send(new invoicePdf($data));
|
||||
}
|
||||
|
||||
$invoice = Invoice::with(['items', 'user', 'invoiceTemplate', 'taxes'])->find($invoice->id);
|
||||
@ -185,7 +196,7 @@ class InvoicesController extends Controller
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
@ -209,7 +220,7 @@ class InvoicesController extends Controller
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function edit(Request $request,$id)
|
||||
{
|
||||
@ -222,12 +233,13 @@ class InvoicesController extends Controller
|
||||
])->find($id);
|
||||
|
||||
return response()->json([
|
||||
'nextInvoiceNumber' => $invoice->invoice_number,
|
||||
'nextInvoiceNumber' => $invoice->getInvoiceNumAttribute(),
|
||||
'invoice' => $invoice,
|
||||
'invoiceTemplates' => InvoiceTemplate::all(),
|
||||
'tax_per_item' => $invoice->tax_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 +248,17 @@ class InvoicesController extends Controller
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
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);
|
||||
$due_date = Carbon::createFromFormat('d/m/Y', $request->due_date);
|
||||
|
||||
@ -268,7 +287,7 @@ class InvoicesController extends Controller
|
||||
|
||||
$invoice->invoice_date = $invoice_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->user_id = $request->user_id;
|
||||
$invoice->invoice_template_id = $request->invoice_template_id;
|
||||
@ -292,7 +311,6 @@ class InvoicesController extends Controller
|
||||
foreach ($oldTaxes as $oldTax) {
|
||||
Tax::destroy($oldTax['id']);
|
||||
}
|
||||
|
||||
foreach ($invoiceItems as $invoiceItem) {
|
||||
$invoiceItem['company_id'] = $request->header('company');
|
||||
$item = $invoice->items()->create($invoiceItem);
|
||||
@ -300,8 +318,7 @@ class InvoicesController extends Controller
|
||||
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
|
||||
foreach ($invoiceItem['taxes'] as $tax) {
|
||||
$tax['company_id'] = $request->header('company');
|
||||
|
||||
if ($tax['amount']) {
|
||||
if (gettype($tax['amount']) !== "NULL") {
|
||||
$item->taxes()->create($tax);
|
||||
}
|
||||
}
|
||||
@ -312,7 +329,7 @@ class InvoicesController extends Controller
|
||||
foreach ($request->taxes as $tax) {
|
||||
$tax['company_id'] = $request->header('company');
|
||||
|
||||
if ($tax['amount']) {
|
||||
if (gettype($tax['amount']) !== "NULL") {
|
||||
$invoice->taxes()->create($tax);
|
||||
}
|
||||
}
|
||||
@ -331,7 +348,7 @@ class InvoicesController extends Controller
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
@ -369,6 +386,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)
|
||||
{
|
||||
$invoice = Invoice::findOrFail($request->id);
|
||||
@ -378,10 +403,6 @@ class InvoicesController extends Controller
|
||||
$data['user'] = User::find($userId)->toArray();
|
||||
$data['company'] = Company::find($invoice->company_id);
|
||||
$email = $data['user']['email'];
|
||||
$notificationEmail = CompanySetting::getSetting(
|
||||
'notification_email',
|
||||
$request->header('company')
|
||||
);
|
||||
|
||||
if (!$email) {
|
||||
return response()->json([
|
||||
@ -389,13 +410,13 @@ class InvoicesController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
if (!$notificationEmail) {
|
||||
if (!config('mail.from.name')) {
|
||||
return response()->json([
|
||||
'error' => 'notification_email_does_not_exist'
|
||||
'error' => 'from_email_does_not_exist'
|
||||
]);
|
||||
}
|
||||
|
||||
\Mail::to($email)->send(new invoicePdf($data, $notificationEmail));
|
||||
\Mail::to($email)->send(new invoicePdf($data));
|
||||
|
||||
if ($invoice->status == Invoice::STATUS_DRAFT) {
|
||||
$invoice->status = Invoice::STATUS_SENT;
|
||||
@ -409,6 +430,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)
|
||||
{
|
||||
$invoice = Invoice::findOrFail($request->id);
|
||||
@ -421,6 +449,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)
|
||||
{
|
||||
$invoice = Invoice::findOrFail($request->id);
|
||||
@ -434,6 +469,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)
|
||||
{
|
||||
$invoices = Invoice::where('paid_status', '<>', Invoice::STATUS_PAID)
|
||||
@ -445,4 +488,94 @@ class InvoicesController extends Controller
|
||||
'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;
|
||||
|
||||
$items = Item::applyFilters($request->only([
|
||||
$items = Item::with(['taxes'])
|
||||
->leftJoin('units', 'units.id', '=', 'items.unit_id')
|
||||
->applyFilters($request->only([
|
||||
'search',
|
||||
'price',
|
||||
'unit',
|
||||
'unit_id',
|
||||
'orderByField',
|
||||
'orderBy'
|
||||
]))
|
||||
->whereCompany($request->header('company'))
|
||||
->select('items.*', 'units.name as unit_name')
|
||||
->latest()
|
||||
->paginate($limit);
|
||||
|
||||
@ -33,7 +36,7 @@ class ItemsController extends Controller
|
||||
|
||||
public function edit(Request $request, $id)
|
||||
{
|
||||
$item = Item::with('taxes')->find($id);
|
||||
$item = Item::with(['taxes', 'unit'])->find($id);
|
||||
|
||||
return response()->json([
|
||||
'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)
|
||||
{
|
||||
$item = new Item();
|
||||
$item->name = $request->name;
|
||||
$item->unit = $request->unit;
|
||||
$item->unit_id = $request->unit_id;
|
||||
$item->description = $request->description;
|
||||
$item->company_id = $request->header('company');
|
||||
$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)
|
||||
{
|
||||
$item = Item::find($id);
|
||||
$item->name = $request->name;
|
||||
$item->unit = $request->unit;
|
||||
$item->unit_id = $request->unit_id;
|
||||
$item->description = $request->description;
|
||||
$item->price = $request->price;
|
||||
$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)
|
||||
{
|
||||
$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)
|
||||
{
|
||||
$items = [];
|
||||
foreach ($request->id as $id) {
|
||||
$item = Item::deleteItem($id);
|
||||
if (!$item) {
|
||||
if ($item) {
|
||||
array_push($items, $id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,29 +3,19 @@ namespace Crater\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Crater\Country;
|
||||
use Crater\State;
|
||||
use Crater\City;
|
||||
|
||||
class LocationController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Retrive a list of Countries.
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getCountries()
|
||||
{
|
||||
return response()->json([
|
||||
'countries' => Country::all()
|
||||
]);
|
||||
}
|
||||
|
||||
public function getStates($id)
|
||||
{
|
||||
return response()->json([
|
||||
'states' => Country::find($id)->states
|
||||
]);
|
||||
}
|
||||
|
||||
public function getCities($id)
|
||||
{
|
||||
return response()->json([
|
||||
'cities' => State::find($id)->cities
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,13 @@ use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
class OnboardingController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Retrieve Onboarding data.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getOnboardingData(Request $request)
|
||||
{
|
||||
if (!\Storage::disk('local')->has('database_created')) {
|
||||
@ -37,9 +44,13 @@ class OnboardingController extends Controller
|
||||
$date_formats = DateFormatter::get_list();
|
||||
$time_zones = TimeZones::get_list();
|
||||
$languages = [
|
||||
["code"=>"ar", "name" => "Arabic"],
|
||||
["code"=>"en", "name" => "English"],
|
||||
["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)"]
|
||||
];
|
||||
$fiscal_years = [
|
||||
['key' => 'january-december' , 'value' => '1-12'],
|
||||
@ -58,8 +69,6 @@ class OnboardingController extends Controller
|
||||
$user = User::with([
|
||||
'addresses',
|
||||
'addresses.country',
|
||||
'addresses.state',
|
||||
'addresses.city',
|
||||
'company'
|
||||
])->find(1);
|
||||
|
||||
@ -74,6 +83,13 @@ class OnboardingController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setup Admin Profile.
|
||||
*
|
||||
* @param \Crater\Http\Requests\ProfileRequest $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function adminProfile(ProfileRequest $request)
|
||||
{
|
||||
$setting = Setting::getSetting('profile_complete');
|
||||
@ -99,6 +115,12 @@ class OnboardingController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup Admin Avatar.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function uploadAdminAvatar(Request $request)
|
||||
{
|
||||
$setting = Setting::getSetting('profile_complete');
|
||||
@ -125,6 +147,12 @@ class OnboardingController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup Admin Company.
|
||||
*
|
||||
* @param \Crater\Http\Requests\CompanyRequest $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function adminCompany(CompanyRequest $request)
|
||||
{
|
||||
$setting = Setting::getSetting('profile_complete');
|
||||
@ -156,8 +184,8 @@ class OnboardingController extends Controller
|
||||
$fields = $request->only([
|
||||
'address_street_1',
|
||||
'address_street_2',
|
||||
'city_id',
|
||||
'state_id',
|
||||
'city',
|
||||
'state',
|
||||
'country_id',
|
||||
'zip',
|
||||
'phone'
|
||||
@ -176,6 +204,13 @@ class OnboardingController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setup Company Settings.
|
||||
*
|
||||
* @param \Crater\Http\Requests\CompanySettingRequest $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function companySettings(CompanySettingRequest $request)
|
||||
{
|
||||
$setting = Setting::getSetting('profile_complete');
|
||||
@ -204,6 +239,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 = [
|
||||
'primary_text_color' => '#5851D8',
|
||||
'heading_text_color' => '#595959',
|
||||
@ -234,13 +308,24 @@ class OnboardingController extends Controller
|
||||
|
||||
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);
|
||||
|
||||
$path = base_path('.env');
|
||||
|
||||
if (file_exists($path)) {
|
||||
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 Crater\CompanySetting;
|
||||
use Crater\Currency;
|
||||
use Crater\Company;
|
||||
use Crater\Invoice;
|
||||
use Crater\Payment;
|
||||
use Crater\PaymentMethod;
|
||||
use Carbon\Carbon;
|
||||
use function MongoDB\BSON\toJSON;
|
||||
use Crater\User;
|
||||
use Crater\Http\Requests\PaymentRequest;
|
||||
use Validator;
|
||||
use Crater\Mail\PaymentPdf;
|
||||
|
||||
class PaymentController extends Controller
|
||||
{
|
||||
@ -22,19 +26,20 @@ class PaymentController extends Controller
|
||||
{
|
||||
$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')
|
||||
->leftJoin('invoices', 'invoices.id', '=', 'payments.invoice_id')
|
||||
->leftJoin('payment_methods', 'payment_methods.id', '=', 'payments.payment_method_id')
|
||||
->applyFilters($request->only([
|
||||
'search',
|
||||
'payment_number',
|
||||
'payment_mode',
|
||||
'payment_method_id',
|
||||
'customer_id',
|
||||
'orderByField',
|
||||
'orderBy'
|
||||
]))
|
||||
->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()
|
||||
->paginate($limit);
|
||||
|
||||
@ -50,13 +55,27 @@ class PaymentController extends Controller
|
||||
*/
|
||||
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([
|
||||
'customers' => User::where('role', 'customer')
|
||||
->whereCompany($request->header('company'))
|
||||
->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)
|
||||
{
|
||||
$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);
|
||||
|
||||
if ($request->has('invoice_id') && $request->invoice_id != null) {
|
||||
@ -90,17 +116,19 @@ class PaymentController extends Controller
|
||||
|
||||
$payment = Payment::create([
|
||||
'payment_date' => $payment_date,
|
||||
'payment_number' => $request->payment_number,
|
||||
'payment_number' => $number_attributes['payment_number'],
|
||||
'user_id' => $request->user_id,
|
||||
'company_id' => $request->header('company'),
|
||||
'invoice_id' => $request->invoice_id,
|
||||
'payment_mode' => $request->payment_mode,
|
||||
'payment_method_id' => $request->payment_method_id,
|
||||
'amount' => $request->amount,
|
||||
'notes' => $request->notes,
|
||||
'unique_hash' => str_random(60)
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'payment' => $payment,
|
||||
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash),
|
||||
'success' => true
|
||||
]);
|
||||
}
|
||||
@ -113,7 +141,12 @@ class PaymentController extends Controller
|
||||
*/
|
||||
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)
|
||||
{
|
||||
$payment = Payment::with('user', 'invoice')->find($id);
|
||||
$payment = Payment::with(['user', 'invoice', 'paymentMethod'])->find($id);
|
||||
|
||||
$invoices = Invoice::where('paid_status', '<>', Invoice::STATUS_PAID)
|
||||
->where('user_id', $payment->user_id)->where('due_amount', '>', 0)
|
||||
@ -135,7 +168,12 @@ class PaymentController extends Controller
|
||||
'customers' => User::where('role', 'customer')
|
||||
->whereCompany($request->header('company'))
|
||||
->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,
|
||||
'invoices' => $invoices
|
||||
]);
|
||||
@ -150,6 +188,13 @@ class PaymentController extends Controller
|
||||
*/
|
||||
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 = Payment::find($id);
|
||||
@ -178,16 +223,17 @@ class PaymentController extends Controller
|
||||
}
|
||||
|
||||
$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->invoice_id = $request->invoice_id;
|
||||
$payment->payment_mode = $request->payment_mode;
|
||||
$payment->payment_method_id = $request->payment_method_id;
|
||||
$payment->amount = $request->amount;
|
||||
$payment->notes = $request->notes;
|
||||
$payment->save();
|
||||
|
||||
return response()->json([
|
||||
'payment' => $payment,
|
||||
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash),
|
||||
'success' => true
|
||||
]);
|
||||
}
|
||||
@ -249,4 +295,37 @@ class PaymentController extends Controller
|
||||
'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'];
|
||||
$notificationEmail = CompanySetting::getSetting(
|
||||
'notification_email',
|
||||
$request->header('company')
|
||||
);
|
||||
|
||||
if (!$email) {
|
||||
return response()->json([
|
||||
'error' => 'user_email_does_not_exist'
|
||||
]);
|
||||
}
|
||||
|
||||
if (!$notificationEmail) {
|
||||
return response()->json([
|
||||
'error' => 'notification_email_does_not_exist'
|
||||
]);
|
||||
}
|
||||
|
||||
\Mail::to($email)->send(new PaymentPdf($data, $notificationEmail));
|
||||
|
||||
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 Crater\Setting;
|
||||
use Crater\Mail\TestMail;
|
||||
use Mail;
|
||||
|
||||
class SettingsController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Retrive App Version.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getAppVersion(Request $request)
|
||||
{
|
||||
$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'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,8 @@ use Crater\User;
|
||||
use Crater\Currency;
|
||||
use Crater\Setting;
|
||||
use Crater\Item;
|
||||
use Crater\PaymentMethod;
|
||||
use Crater\Unit;
|
||||
use Crater\TaxType;
|
||||
use DB;
|
||||
use Carbon\Carbon;
|
||||
@ -46,10 +48,18 @@ class UsersController extends Controller
|
||||
$request->header('company')
|
||||
);
|
||||
|
||||
$items = Item::all();
|
||||
$items = Item::with('taxes')->get();
|
||||
|
||||
$taxTypes = TaxType::latest()->get();
|
||||
|
||||
$paymentMethods = PaymentMethod::whereCompany($request->header('company'))
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
$units = Unit::whereCompany($request->header('company'))
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'user' => $user,
|
||||
'customers' => $customers,
|
||||
@ -61,6 +71,8 @@ class UsersController extends Controller
|
||||
'items' => $items,
|
||||
'taxTypes' => $taxTypes,
|
||||
'moment_date_format' => $moment_date_format,
|
||||
'paymentMethods' => $paymentMethods,
|
||||
'units' => $units,
|
||||
'fiscal_year' => $fiscal_year,
|
||||
]);
|
||||
}
|
||||
|
||||
@ -25,7 +25,6 @@ class EstimatesRequest extends FormRequest
|
||||
$rules = [
|
||||
'estimate_date' => 'required',
|
||||
'expiry_date' => 'required',
|
||||
'estimate_number' => 'required|unique:estimates,estimate_number',
|
||||
'user_id' => 'required',
|
||||
'discount' => 'required',
|
||||
'discount_val' => 'required',
|
||||
@ -41,10 +40,6 @@ class EstimatesRequest extends FormRequest
|
||||
'items.*.price' => 'required'
|
||||
];
|
||||
|
||||
if ($this->getMethod() == 'PUT') {
|
||||
$rules['estimate_number'] = $rules['estimate_number'].','.$this->get('id');
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,6 @@ class InvoicesRequest extends FormRequest
|
||||
$rules = [
|
||||
'invoice_date' => 'required',
|
||||
'due_date' => 'required',
|
||||
'invoice_number' => 'required|unique:invoices,invoice_number',
|
||||
'user_id' => 'required',
|
||||
'discount' => 'required',
|
||||
'discount_val' => 'required',
|
||||
@ -41,10 +40,6 @@ class InvoicesRequest extends FormRequest
|
||||
'items.*.price' => 'required'
|
||||
];
|
||||
|
||||
if ($this->getMethod() == 'PUT') {
|
||||
$rules['invoice_number'] = $rules['invoice_number'].','.$this->get('id');
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,12 +40,9 @@ class MailEnvironmentRequest extends FormRequest
|
||||
case 'mailgun':
|
||||
return [
|
||||
'mail_driver' => 'required|string',
|
||||
'mail_host' => 'required|string',
|
||||
'mail_port' => 'required',
|
||||
'mail_mailgun_domain' => 'required|string',
|
||||
'mail_mailgun_secret' => 'required|string',
|
||||
'mail_mailgun_endpoint' => 'required|string',
|
||||
'mail_encryption' => 'required|string',
|
||||
'from_name' => '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 = [
|
||||
'payment_date' => 'required',
|
||||
'payment_number' => 'required|unique:payments,payment_number',
|
||||
'user_id' => 'required',
|
||||
'amount' => 'required',
|
||||
];
|
||||
|
||||
if ($this->getMethod() == 'PUT') {
|
||||
$rules['payment_number'] = $rules['payment_number'].','.$this->route('payment');
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ class ProfileRequest extends FormRequest
|
||||
case 'POST':
|
||||
return [
|
||||
'name' => 'required',
|
||||
'password' => 'required',
|
||||
'password' => 'required|min:8',
|
||||
'address_street_1' => 'max:255',
|
||||
'address_street_2' => 'max:255',
|
||||
'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'
|
||||
];
|
||||
|
||||
public static function getNextInvoiceNumber()
|
||||
public static function getNextInvoiceNumber($value)
|
||||
{
|
||||
// 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) {
|
||||
// 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.
|
||||
@ -82,7 +86,7 @@ class Invoice extends Model
|
||||
// So the substr returns this 000001
|
||||
|
||||
// Add the string in front and higher up the number.
|
||||
// the %05d part makes sure that there are always 6 numbers in the string.
|
||||
// the %06d part makes sure that there are always 6 numbers in the string.
|
||||
// so it adds the missing zero's when needed.
|
||||
|
||||
return sprintf('%06d', intval($number) + 1);
|
||||
@ -143,10 +147,15 @@ class Invoice extends Model
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public function getInvoicePrefixAttribute () {
|
||||
$prefix = explode("-", $this->invoice_number)[0];
|
||||
return $prefix;
|
||||
}
|
||||
|
||||
public function getFormattedCreatedAtAttribute($value)
|
||||
{
|
||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id);
|
||||
|
||||
@ -30,6 +30,7 @@ class InvoiceItem extends Model
|
||||
'price' => 'integer',
|
||||
'total' => 'integer',
|
||||
'discount' => 'float',
|
||||
'quantity' => 'float',
|
||||
'discount_val' => 'integer',
|
||||
'tax' => 'integer'
|
||||
];
|
||||
|
||||
19
app/Item.php
19
app/Item.php
@ -24,19 +24,24 @@ class Item extends Model
|
||||
'formattedCreatedAt'
|
||||
];
|
||||
|
||||
public function unit()
|
||||
{
|
||||
return $this->belongsTo(Unit::class);
|
||||
}
|
||||
|
||||
public function scopeWhereSearch($query, $search)
|
||||
{
|
||||
return $query->where('name', 'LIKE', '%'.$search.'%');
|
||||
return $query->where('items.name', 'LIKE', '%'.$search.'%');
|
||||
}
|
||||
|
||||
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)
|
||||
@ -56,8 +61,8 @@ class Item extends Model
|
||||
$query->wherePrice($filters->get('price'));
|
||||
}
|
||||
|
||||
if ($filters->get('unit')) {
|
||||
$query->whereUnit($filters->get('unit'));
|
||||
if ($filters->get('unit_id')) {
|
||||
$query->whereUnit($filters->get('unit_id'));
|
||||
}
|
||||
|
||||
if ($filters->get('orderByField') || $filters->get('orderBy')) {
|
||||
@ -80,7 +85,7 @@ class Item extends Model
|
||||
|
||||
public function scopeWhereCompany($query, $company_id)
|
||||
{
|
||||
$query->where('company_id', $company_id);
|
||||
$query->where('items.company_id', $company_id);
|
||||
}
|
||||
|
||||
public function invoiceItems()
|
||||
|
||||
@ -15,7 +15,7 @@ class Listener
|
||||
protected function isListenerFired($event)
|
||||
{
|
||||
// Do not apply to the same or newer versions
|
||||
if (version_compare(static::VERSION, $event->old, '<')) {
|
||||
if (version_compare(static::VERSION, $event->old, '<=')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
109
app/Listeners/Updates/v2/Version200.php
Normal file
109
app/Listeners/Updates/v2/Version200.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Listeners\Updates\v2;
|
||||
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Crater\Listeners\Updates\Listener;
|
||||
use Crater\Events\UpdateFinished;
|
||||
use Crater\Setting;
|
||||
use Crater\Address;
|
||||
|
||||
class Version200 extends Listener
|
||||
{
|
||||
const VERSION = '2.0.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;
|
||||
}
|
||||
|
||||
// Replace state and city id to name
|
||||
$this->replaceStateAndCityName();
|
||||
|
||||
// Drop states and cities foreign key
|
||||
$this->dropForeignKey();
|
||||
|
||||
// Remove states and cities tables
|
||||
$this->dropSchemas();
|
||||
|
||||
// Delete state & city models, migrations & seeders
|
||||
$this->deleteFiles();
|
||||
|
||||
// Update Crater app version
|
||||
$this->updateVersion();
|
||||
}
|
||||
|
||||
private function replaceStateAndCityName() {
|
||||
\Schema::table('addresses', function (Blueprint $table) {
|
||||
$table->string('state')->nullable();
|
||||
$table->string('city')->nullable();
|
||||
});
|
||||
|
||||
$addresses = \Crater\Address::all();
|
||||
foreach ($addresses as $add) {
|
||||
$city = \Crater\City::find($add->city_id);
|
||||
if($city) {
|
||||
$add->city = $city->name;
|
||||
}
|
||||
|
||||
$state = \Crater\State::find($add->state_id);
|
||||
if($state) {
|
||||
$add->state = $state->name;
|
||||
}
|
||||
|
||||
$add->save();
|
||||
}
|
||||
}
|
||||
|
||||
private function dropForeignKey() {
|
||||
\Schema::table('addresses', function (Blueprint $table) {
|
||||
$table->dropForeign('addresses_state_id_foreign');
|
||||
$table->dropForeign('addresses_city_id_foreign');
|
||||
$table->dropColumn('state_id');
|
||||
$table->dropColumn('city_id');
|
||||
});
|
||||
}
|
||||
|
||||
private function dropSchemas() {
|
||||
\Schema::disableForeignKeyConstraints();
|
||||
|
||||
\Schema::dropIfExists('states');
|
||||
\Schema::dropIfExists('cities');
|
||||
|
||||
\Schema::enableForeignKeyConstraints();
|
||||
}
|
||||
|
||||
private function deleteFiles() {
|
||||
\File::delete(
|
||||
database_path('migrations/2017_05_06_172817_create_cities_table.php'),
|
||||
database_path('migrations/2017_05_06_173711_create_states_table.php'),
|
||||
database_path('seeds/StatesTableSeeder.php'),
|
||||
database_path('seeds/CitiesTableSeeder.php'),
|
||||
app_path('City.php'),
|
||||
app_path('State.php')
|
||||
);
|
||||
}
|
||||
|
||||
private function updateVersion() {
|
||||
Setting::setSetting('version', static::VERSION);
|
||||
}
|
||||
}
|
||||
87
app/Listeners/Updates/v2/Version201.php
Normal file
87
app/Listeners/Updates/v2/Version201.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Listeners\Updates\v2;
|
||||
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Crater\Events\UpdateFinished;
|
||||
use Crater\Listeners\Updates\Listener;
|
||||
use Crater\Setting;
|
||||
|
||||
class Version201 extends Listener
|
||||
{
|
||||
const VERSION = '2.0.1';
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
// Remove the language files
|
||||
$this->removeLanguageFiles();
|
||||
|
||||
// Change estimate & invoice migrations
|
||||
$this->changeMigrations();
|
||||
|
||||
// Update Crater app version
|
||||
Setting::setSetting('version', static::VERSION);
|
||||
}
|
||||
|
||||
private function removeLanguageFiles() {
|
||||
$en = resource_path('assets/js/plugins/en.js');
|
||||
$es = resource_path('assets/js/plugins/es.js');
|
||||
$fr = resource_path('assets/js/plugins/fr.js');
|
||||
|
||||
if(file_exists($en)) {
|
||||
unlink($en);
|
||||
}
|
||||
|
||||
if(file_exists($es)) {
|
||||
unlink($es);
|
||||
}
|
||||
|
||||
if(file_exists($fr)) {
|
||||
unlink($fr);
|
||||
}
|
||||
}
|
||||
|
||||
private function changeMigrations()
|
||||
{
|
||||
\Schema::table('invoices', function (Blueprint $table) {
|
||||
$table->decimal('discount', 15, 2)->nullable()->change();
|
||||
});
|
||||
|
||||
\Schema::table('estimates', function (Blueprint $table) {
|
||||
$table->decimal('discount', 15, 2)->nullable()->change();
|
||||
});
|
||||
|
||||
\Schema::table('invoice_items', function (Blueprint $table) {
|
||||
$table->decimal('quantity', 15, 2)->change();
|
||||
$table->decimal('discount', 15, 2)->nullable()->change();
|
||||
});
|
||||
|
||||
\Schema::table('estimate_items', function (Blueprint $table) {
|
||||
$table->decimal('quantity', 15, 2)->change();
|
||||
$table->decimal('discount', 15, 2)->nullable()->change();
|
||||
$table->unsignedBigInteger('discount_val')->nullable()->change();
|
||||
});
|
||||
}
|
||||
}
|
||||
40
app/Listeners/Updates/v2/Version202.php
Normal file
40
app/Listeners/Updates/v2/Version202.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?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;
|
||||
|
||||
class Version202 extends Listener
|
||||
{
|
||||
const VERSION = '2.0.2';
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
// Update Crater app version
|
||||
Setting::setSetting('version', static::VERSION);
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,17 +12,14 @@ class EstimatePdf extends Mailable
|
||||
|
||||
public $data = [];
|
||||
|
||||
public $notificationEmail = '';
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($data, $notificationEmail)
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->notificationEmail = $notificationEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -32,6 +29,6 @@ class EstimatePdf extends Mailable
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->from($this->notificationEmail)->markdown('emails.send.estimate', ['data', $this->data]);
|
||||
return $this->markdown('emails.send.estimate', ['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 = [];
|
||||
|
||||
public $notificationEmail = '';
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($data, $notificationEmail)
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->notificationEmail = $notificationEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->from($this->notificationEmail)->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
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -12,17 +12,14 @@ class invoicePdf extends Mailable
|
||||
|
||||
public $data = [];
|
||||
|
||||
public $notificationEmail = '';
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($data, $notificationEmail)
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->notificationEmail = $notificationEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -32,6 +29,6 @@ class invoicePdf extends Mailable
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->from($this->notificationEmail)->markdown('emails.send.invoice', ['data', $this->data]);
|
||||
return $this->markdown('emails.send.invoice', ['data', $this->data]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ use Crater\User;
|
||||
use Crater\Invoice;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Crater\PaymentMethod;
|
||||
|
||||
class Payment extends Model
|
||||
{
|
||||
@ -19,9 +20,11 @@ class Payment extends Model
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'invoice_id',
|
||||
'payment_method_id',
|
||||
'payment_date',
|
||||
'company_id',
|
||||
'notes',
|
||||
'unique_hash',
|
||||
'payment_number',
|
||||
'payment_mode',
|
||||
'amount'
|
||||
@ -32,10 +35,34 @@ class Payment extends Model
|
||||
'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
|
||||
$payment = Payment::orderBy('created_at', 'desc')->first();
|
||||
$payment = Payment::where('payment_number', 'LIKE', $value . '-%')
|
||||
->orderBy('created_at', 'desc')
|
||||
->first();
|
||||
if (!$payment) {
|
||||
// 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.
|
||||
@ -54,6 +81,12 @@ class Payment extends Model
|
||||
return sprintf('%06d', intval($number) + 1);
|
||||
}
|
||||
|
||||
public function getPaymentPrefixAttribute ()
|
||||
{
|
||||
$prefix= explode("-",$this->payment_number)[0];
|
||||
return $prefix;
|
||||
}
|
||||
|
||||
public function invoice()
|
||||
{
|
||||
return $this->belongsTo(Invoice::class);
|
||||
@ -64,6 +97,11 @@ class Payment extends Model
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function paymentMethod()
|
||||
{
|
||||
return $this->belongsTo(PaymentMethod::class);
|
||||
}
|
||||
|
||||
public function getFormattedCreatedAtAttribute($value)
|
||||
{
|
||||
$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.'%');
|
||||
}
|
||||
|
||||
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)
|
||||
@ -109,8 +147,8 @@ class Payment extends Model
|
||||
$query->paymentNumber($filters->get('payment_number'));
|
||||
}
|
||||
|
||||
if ($filters->get('payment_mode')) {
|
||||
$query->paymentMode($filters->get('payment_mode'));
|
||||
if ($filters->get('payment_method_id')) {
|
||||
$query->paymentMethod($filters->get('payment_method_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);
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,11 @@ use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
||||
use Crater\Events\UpdateFinished;
|
||||
use Crater\Listeners\Updates\v1\Version110;
|
||||
use Crater\Listeners\Updates\v2\Version200;
|
||||
use Crater\Listeners\Updates\v2\Version201;
|
||||
use Crater\Listeners\Updates\v2\Version202;
|
||||
use Crater\Listeners\Updates\v2\Version210;
|
||||
use Crater\Listeners\Updates\v3\Version300;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
@ -17,6 +22,11 @@ class EventServiceProvider extends ServiceProvider
|
||||
protected $listen = [
|
||||
UpdateFinished::class=> [
|
||||
Version110::class,
|
||||
Version200::class,
|
||||
Version201::class,
|
||||
Version202::class,
|
||||
Version210::class,
|
||||
Version300::class,
|
||||
],
|
||||
Registered::class => [
|
||||
SendEmailVerificationNotification::class,
|
||||
|
||||
@ -38,7 +38,7 @@ class EnvironmentManager
|
||||
'DB_PORT='.config('database.connections.'.config('database.default').'.port')."\n".
|
||||
'DB_DATABASE='.config('database.connections.'.config('database.default').'.database')."\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 =
|
||||
'DB_CONNECTION='.$request->database_connection."\n".
|
||||
@ -46,19 +46,23 @@ class EnvironmentManager
|
||||
'DB_PORT='.$request->database_port."\n".
|
||||
'DB_DATABASE='.$request->database_name."\n".
|
||||
'DB_USERNAME='.$request->database_username."\n".
|
||||
'DB_PASSWORD='.$request->database_password."\n\n";
|
||||
'DB_PASSWORD="'.$request->database_password."\"\n\n";
|
||||
|
||||
if (! $this->checkDatabaseConnection($request)) {
|
||||
try {
|
||||
|
||||
$this->checkDatabaseConnection($request);
|
||||
|
||||
return [
|
||||
'error' => 'connection_failed'
|
||||
];
|
||||
} else {
|
||||
if(\Schema::hasTable('users') ) {
|
||||
return [
|
||||
'error' => 'database_should_be_empty'
|
||||
];
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
|
||||
return [
|
||||
'error_message' => $e->getMessage()
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
@ -118,8 +122,6 @@ class EnvironmentManager
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'error' => 'mail_variables_save_error'
|
||||
@ -316,12 +318,6 @@ class EnvironmentManager
|
||||
],
|
||||
]);
|
||||
|
||||
try {
|
||||
DB::connection()->getPdo();
|
||||
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
return DB::connection()->getPdo();
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,13 @@ class Updater
|
||||
$data = null;
|
||||
$path = null;
|
||||
|
||||
$url = 'https://craterapp.com/downloads/file/'.$version.'?type=update';
|
||||
if(env('APP_ENV') === 'development')
|
||||
{
|
||||
$url = 'https://craterapp.com/downloads/file/'.$version.'?type=update&is_dev=1';
|
||||
} else {
|
||||
$url = 'https://craterapp.com/downloads/file/'.$version.'?type=update';
|
||||
}
|
||||
|
||||
|
||||
$response = static::getRemote($url, ['timeout' => 100, 'track_redirects' => true]);
|
||||
|
||||
@ -115,7 +121,12 @@ class Updater
|
||||
public static function checkForUpdate()
|
||||
{
|
||||
$data = null;
|
||||
$url = 'https://craterapp.com/downloads/check/latest/'. Setting::getSetting('version') . '?type=update';
|
||||
if(env('APP_ENV') === 'development')
|
||||
{
|
||||
$url = 'https://craterapp.com/downloads/check/latest/'. Setting::getSetting('version') . '?type=update&is_dev=1';
|
||||
} else {
|
||||
$url = 'https://craterapp.com/downloads/check/latest/'. Setting::getSetting('version') . '?type=update';
|
||||
}
|
||||
|
||||
$response = static::getRemote($url, ['timeout' => 100, 'track_redirects' => true]);
|
||||
|
||||
|
||||
@ -41,10 +41,14 @@ function clean_slug($string)
|
||||
* @param $money
|
||||
* @return formated_money
|
||||
*/
|
||||
function format_money_pdf($money)
|
||||
function format_money_pdf($money, $currency = null)
|
||||
{
|
||||
$money = $money / 100;
|
||||
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', 1));
|
||||
|
||||
if (!$currency) {
|
||||
$currency = Currency::findOrFail(CompanySetting::getSetting('currency', 1));
|
||||
}
|
||||
|
||||
$format_money = number_format(
|
||||
$money,
|
||||
$currency->precision,
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
namespace Crater;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Crater\City;
|
||||
use Crater\Country;
|
||||
use Crater\Address;
|
||||
|
||||
class State extends Model
|
||||
{
|
||||
public function cities()
|
||||
{
|
||||
return $this->hasMany(City::class);
|
||||
}
|
||||
|
||||
public function country()
|
||||
{
|
||||
return $this->belongsTo(Country::class);
|
||||
}
|
||||
|
||||
public function address()
|
||||
{
|
||||
return $this->hasMany(Address::class);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@
|
||||
"require": {
|
||||
"php": "^7.2",
|
||||
"barryvdh/laravel-dompdf": "^0.8.1",
|
||||
"doctrine/dbal": "^2.10",
|
||||
"fideloper/proxy": "^4.0",
|
||||
"guzzlehttp/guzzle": "^6.3",
|
||||
"intervention/image": "^2.3",
|
||||
|
||||
484
composer.lock
generated
484
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "2a5e8d91a2be3144e2812dd708dc14b7",
|
||||
"content-hash": "e7cf4f0a8e1e7d60cc72b34ed4c730ce",
|
||||
"packages": [
|
||||
{
|
||||
"name": "barryvdh/laravel-dompdf",
|
||||
@ -158,6 +158,247 @@
|
||||
"description": "implementation of xdg base directory specification for php",
|
||||
"time": "2014-10-24T07:27:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/cache",
|
||||
"version": "v1.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/cache.git",
|
||||
"reference": "d4374ae95b36062d02ef310100ed33d78738d76c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/cache/zipball/d4374ae95b36062d02ef310100ed33d78738d76c",
|
||||
"reference": "d4374ae95b36062d02ef310100ed33d78738d76c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "~7.1"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/common": ">2.2,<2.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"alcaeus/mongo-php-adapter": "^1.1",
|
||||
"doctrine/coding-standard": "^4.0",
|
||||
"mongodb/mongodb": "^1.1",
|
||||
"phpunit/phpunit": "^7.0",
|
||||
"predis/predis": "~1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.8.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Caching library offering an object-oriented API for many cache backends",
|
||||
"homepage": "https://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"cache",
|
||||
"caching"
|
||||
],
|
||||
"time": "2019-10-28T09:31:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "v2.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/dbal.git",
|
||||
"reference": "0c9a646775ef549eb0a213a4f9bd4381d9b4d934"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/0c9a646775ef549eb0a213a4f9bd4381d9b4d934",
|
||||
"reference": "0c9a646775ef549eb0a213a4f9bd4381d9b4d934",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/cache": "^1.0",
|
||||
"doctrine/event-manager": "^1.0",
|
||||
"ext-pdo": "*",
|
||||
"php": "^7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^6.0",
|
||||
"jetbrains/phpstorm-stubs": "^2019.1",
|
||||
"phpstan/phpstan": "^0.11.3",
|
||||
"phpunit/phpunit": "^8.4.1",
|
||||
"symfony/console": "^2.0.5|^3.0|^4.0|^5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For helpful console commands such as SQL execution and import of files."
|
||||
},
|
||||
"bin": [
|
||||
"bin/doctrine-dbal"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.10.x-dev",
|
||||
"dev-develop": "3.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\DBAL\\": "lib/Doctrine/DBAL"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
|
||||
"homepage": "https://www.doctrine-project.org/projects/dbal.html",
|
||||
"keywords": [
|
||||
"abstraction",
|
||||
"database",
|
||||
"db2",
|
||||
"dbal",
|
||||
"mariadb",
|
||||
"mssql",
|
||||
"mysql",
|
||||
"oci8",
|
||||
"oracle",
|
||||
"pdo",
|
||||
"pgsql",
|
||||
"postgresql",
|
||||
"queryobject",
|
||||
"sasql",
|
||||
"sql",
|
||||
"sqlanywhere",
|
||||
"sqlite",
|
||||
"sqlserver",
|
||||
"sqlsrv"
|
||||
],
|
||||
"time": "2019-11-03T16:50:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/event-manager",
|
||||
"version": "v1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/event-manager.git",
|
||||
"reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/event-manager/zipball/a520bc093a0170feeb6b14e9d83f3a14452e64b3",
|
||||
"reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/common": "<2.9@dev"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^4.0",
|
||||
"phpunit/phpunit": "^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\": "lib/Doctrine/Common"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Marco Pivetta",
|
||||
"email": "ocramius@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Doctrine Event Manager component",
|
||||
"homepage": "https://www.doctrine-project.org/projects/event-manager.html",
|
||||
"keywords": [
|
||||
"event",
|
||||
"eventdispatcher",
|
||||
"eventmanager"
|
||||
],
|
||||
"time": "2018-06-11T11:59:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/inflector",
|
||||
"version": "v1.3.0",
|
||||
@ -5307,247 +5548,6 @@
|
||||
],
|
||||
"time": "2019-05-27T17:52:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/cache",
|
||||
"version": "v1.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/cache.git",
|
||||
"reference": "d4374ae95b36062d02ef310100ed33d78738d76c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/cache/zipball/d4374ae95b36062d02ef310100ed33d78738d76c",
|
||||
"reference": "d4374ae95b36062d02ef310100ed33d78738d76c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "~7.1"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/common": ">2.2,<2.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"alcaeus/mongo-php-adapter": "^1.1",
|
||||
"doctrine/coding-standard": "^4.0",
|
||||
"mongodb/mongodb": "^1.1",
|
||||
"phpunit/phpunit": "^7.0",
|
||||
"predis/predis": "~1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.8.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Caching library offering an object-oriented API for many cache backends",
|
||||
"homepage": "https://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"cache",
|
||||
"caching"
|
||||
],
|
||||
"time": "2019-10-28T09:31:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "v2.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/dbal.git",
|
||||
"reference": "0c9a646775ef549eb0a213a4f9bd4381d9b4d934"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/0c9a646775ef549eb0a213a4f9bd4381d9b4d934",
|
||||
"reference": "0c9a646775ef549eb0a213a4f9bd4381d9b4d934",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/cache": "^1.0",
|
||||
"doctrine/event-manager": "^1.0",
|
||||
"ext-pdo": "*",
|
||||
"php": "^7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^6.0",
|
||||
"jetbrains/phpstorm-stubs": "^2019.1",
|
||||
"phpstan/phpstan": "^0.11.3",
|
||||
"phpunit/phpunit": "^8.4.1",
|
||||
"symfony/console": "^2.0.5|^3.0|^4.0|^5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For helpful console commands such as SQL execution and import of files."
|
||||
},
|
||||
"bin": [
|
||||
"bin/doctrine-dbal"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.10.x-dev",
|
||||
"dev-develop": "3.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\DBAL\\": "lib/Doctrine/DBAL"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
|
||||
"homepage": "https://www.doctrine-project.org/projects/dbal.html",
|
||||
"keywords": [
|
||||
"abstraction",
|
||||
"database",
|
||||
"db2",
|
||||
"dbal",
|
||||
"mariadb",
|
||||
"mssql",
|
||||
"mysql",
|
||||
"oci8",
|
||||
"oracle",
|
||||
"pdo",
|
||||
"pgsql",
|
||||
"postgresql",
|
||||
"queryobject",
|
||||
"sasql",
|
||||
"sql",
|
||||
"sqlanywhere",
|
||||
"sqlite",
|
||||
"sqlserver",
|
||||
"sqlsrv"
|
||||
],
|
||||
"time": "2019-11-03T16:50:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/event-manager",
|
||||
"version": "v1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/event-manager.git",
|
||||
"reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/event-manager/zipball/a520bc093a0170feeb6b14e9d83f3a14452e64b3",
|
||||
"reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/common": "<2.9@dev"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^4.0",
|
||||
"phpunit/phpunit": "^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\": "lib/Doctrine/Common"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Marco Pivetta",
|
||||
"email": "ocramius@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Doctrine Event Manager component",
|
||||
"homepage": "https://www.doctrine-project.org/projects/event-manager.html",
|
||||
"keywords": [
|
||||
"event",
|
||||
"eventdispatcher",
|
||||
"eventmanager"
|
||||
],
|
||||
"time": "2018-06-11T11:59:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "1.2.0",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
|
||||
@ -9,6 +9,6 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'version' => '1.1.0',
|
||||
'version' => '3.0.0',
|
||||
|
||||
];
|
||||
|
||||
@ -51,7 +51,7 @@ return [
|
||||
'collation' => 'utf8_unicode_ci',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'strict' => false,
|
||||
'engine' => null,
|
||||
],
|
||||
|
||||
|
||||
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,
|
||||
),
|
||||
|
||||
|
||||
);
|
||||
@ -10,9 +10,9 @@ $factory->define(Address::class, function (Faker $faker) {
|
||||
'name' => $faker->name,
|
||||
'address_street_1' => $faker->streetAddress,
|
||||
'address_street_2' => $faker->streetAddress,
|
||||
'city_id' => 5909,
|
||||
'state_id' => 42,
|
||||
'country_id' => 1,
|
||||
'city' => $faker->city,
|
||||
'state' => $faker->state,
|
||||
'country_id' => 231,
|
||||
'zip' => $faker->postcode,
|
||||
'phone' => $faker->phoneNumber,
|
||||
'fax' => $faker->phoneNumber,
|
||||
|
||||
16
database/migrations/2017_05_06_173711_create_states_table.php → database/migrations/2017_04_11_064308_create_units_table.php
Executable file → Normal file
16
database/migrations/2017_05_06_173711_create_states_table.php → database/migrations/2017_04_11_064308_create_units_table.php
Executable file → Normal file
@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateStatesTable extends Migration
|
||||
class CreateUnitsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
@ -13,10 +13,12 @@ class CreateStatesTable extends Migration
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('states', function (Blueprint $table) {
|
||||
$table->increments('id')->index();
|
||||
Schema::create('units', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->integer('country_id');
|
||||
$table->integer('company_id')->unsigned()->nullable();
|
||||
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
@ -27,6 +29,6 @@ class CreateStatesTable extends Migration
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('states');
|
||||
Schema::dropIfExists('units');
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,8 @@ class CreateItemsTable extends Migration
|
||||
$table->unsignedBigInteger('price');
|
||||
$table->integer('company_id')->unsigned()->nullable();
|
||||
$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();
|
||||
});
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ class CreateInvoicesTable extends Migration
|
||||
$table->string('discount_per_item');
|
||||
$table->text('notes')->nullable();
|
||||
$table->string('discount_type')->nullable();
|
||||
$table->unsignedBigInteger('discount')->nullable();
|
||||
$table->decimal('discount', 15, 2)->nullable();
|
||||
$table->unsignedBigInteger('discount_val')->nullable();
|
||||
$table->unsignedBigInteger('sub_total');
|
||||
$table->unsignedBigInteger('total');
|
||||
|
||||
@ -18,10 +18,10 @@ class CreateInvoiceItemsTable extends Migration
|
||||
$table->string('name');
|
||||
$table->string('description')->nullable();
|
||||
$table->string('discount_type');
|
||||
$table->unsignedBigInteger('quantity');
|
||||
$table->unsignedBigInteger('price');
|
||||
$table->decimal('quantity', 15, 2);
|
||||
$table->decimal('discount', 15, 2)->nullable();
|
||||
$table->unsignedBigInteger('discount_val');
|
||||
$table->unsignedBigInteger('discount');
|
||||
$table->unsignedBigInteger('tax');
|
||||
$table->unsignedBigInteger('total');
|
||||
$table->integer('invoice_id')->unsigned();
|
||||
|
||||
@ -23,8 +23,8 @@ class CreateEstimatesTable extends Migration
|
||||
$table->string('tax_per_item');
|
||||
$table->string('discount_per_item');
|
||||
$table->string('notes')->nullable();
|
||||
$table->decimal('discount', 15, 2)->nullable();
|
||||
$table->string('discount_type')->nullable();
|
||||
$table->unsignedBigInteger('discount')->nullable();
|
||||
$table->unsignedBigInteger('discount_val')->nullable();
|
||||
$table->unsignedBigInteger('sub_total');
|
||||
$table->unsignedBigInteger('total');
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateCitiesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('cities', function (Blueprint $table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id')->index();
|
||||
$table->string('name');
|
||||
$table->integer('state_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('cities');
|
||||
}
|
||||
}
|
||||
@ -18,9 +18,9 @@ class CreateEstimateItemsTable extends Migration
|
||||
$table->string('name');
|
||||
$table->string('description')->nullable();
|
||||
$table->string('discount_type');
|
||||
$table->unsignedBigInteger('quantity');
|
||||
$table->unsignedBigInteger('discount');
|
||||
$table->unsignedBigInteger('discount_val');
|
||||
$table->decimal('quantity', 15, 2);
|
||||
$table->decimal('discount', 15, 2)->nullable();
|
||||
$table->unsignedBigInteger('discount_val')->nullable();
|
||||
$table->unsignedBigInteger('price');
|
||||
$table->unsignedBigInteger('tax');
|
||||
$table->unsignedBigInteger('total');
|
||||
|
||||
@ -30,6 +30,6 @@ class CreateExpenseCategoriesTable extends Migration
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('expenses_categories');
|
||||
Schema::dropIfExists('expense_categories');
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,10 +18,8 @@ class CreateAddressesTable extends Migration
|
||||
$table->string('name')->nullable();
|
||||
$table->string('address_street_1')->nullable();
|
||||
$table->string('address_street_2')->nullable();
|
||||
$table->integer('city_id')->unsigned()->nullable();
|
||||
$table->foreign('city_id')->references('id')->on('cities');
|
||||
$table->integer('state_id')->unsigned()->nullable();
|
||||
$table->foreign('state_id')->references('id')->on('states');
|
||||
$table->string('city')->nullable();
|
||||
$table->string('state')->nullable();
|
||||
$table->integer('country_id')->unsigned()->nullable();
|
||||
$table->foreign('country_id')->references('id')->on('countries');
|
||||
$table->string('zip')->nullable();
|
||||
@ -41,6 +39,6 @@ class CreateAddressesTable extends Migration
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('address');
|
||||
Schema::dropIfExists('addresses');
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
<?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()
|
||||
{
|
||||
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) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('payment_number');
|
||||
$table->string('payment_mode')->nullable();
|
||||
$table->date('payment_date');
|
||||
$table->text('notes')->nullable();
|
||||
$table->unsignedBigInteger('amount');
|
||||
$table->string('unique_hash')->nullable();
|
||||
$table->integer('user_id')->unsigned();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->integer('invoice_id')->unsigned()->nullable();
|
||||
$table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
|
||||
$table->integer('company_id')->unsigned()->nullable();
|
||||
$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();
|
||||
});
|
||||
}
|
||||
|
||||
@ -20,9 +20,9 @@ class CreateMediaTable extends Migration
|
||||
$table->string('mime_type')->nullable();
|
||||
$table->string('disk');
|
||||
$table->unsignedInteger('size');
|
||||
$table->json('manipulations');
|
||||
$table->json('custom_properties');
|
||||
$table->json('responsive_images');
|
||||
$table->text('manipulations');
|
||||
$table->text('custom_properties');
|
||||
$table->text('responsive_images');
|
||||
$table->unsignedInteger('order_column')->nullable();
|
||||
$table->nullableTimestamps();
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -524,6 +524,14 @@ class CurrenciesTableSeeder extends Seeder
|
||||
'thousand_separator' => '.',
|
||||
'decimal_separator' => ','
|
||||
],
|
||||
[
|
||||
'name' => 'Serbian Dinar',
|
||||
'code' => 'RSD',
|
||||
'symbol' => 'RSD',
|
||||
'precision' => '2',
|
||||
'thousand_separator' => '.',
|
||||
'decimal_separator' => ','
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($currencies as $currency) {
|
||||
|
||||
@ -14,8 +14,6 @@ class DatabaseSeeder extends Seeder
|
||||
$this->call(CurrenciesTableSeeder::class);
|
||||
$this->call(RoleSeeder::class);
|
||||
$this->call(CountriesTableSeeder::class);
|
||||
$this->call(StatesTableSeeder::class);
|
||||
$this->call(CitiesTableSeeder::class);
|
||||
$this->call(EstimateTemplateSeeder::class);
|
||||
$this->call(InvoiceTemplateSeeder::class);
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
package-lock.json
generated
15
package-lock.json
generated
@ -17428,6 +17428,16 @@
|
||||
"resolved": "https://registry.npmjs.org/v-money/-/v-money-0.8.1.tgz",
|
||||
"integrity": "sha512-raz87AP5F2YEpv1GAocI3SC/y9af1+TQeZQIhAK5UNovho6dnh6RQBa5UG8ZNC+BPLpUh5VECi7EWTjr4+4s1g=="
|
||||
},
|
||||
"v-tooltip": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/v-tooltip/-/v-tooltip-2.0.2.tgz",
|
||||
"integrity": "sha512-xQ+qzOFfywkLdjHknRPgMMupQNS8yJtf9Utd5Dxiu/0n4HtrxqsgDtN2MLZ0LKbburtSAQgyypuE/snM8bBZhw==",
|
||||
"requires": {
|
||||
"lodash": "^4.17.11",
|
||||
"popper.js": "^1.15.0",
|
||||
"vue-resize": "^0.4.5"
|
||||
}
|
||||
},
|
||||
"v8-compile-cache": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz",
|
||||
@ -17515,6 +17525,11 @@
|
||||
"resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-2.1.6.tgz",
|
||||
"integrity": "sha512-s7jmZPlm9FeueJg1RwJtnE9KNPtME/7C8uRWSfp9/yEN4M8XcS/d+bddoyVwVnvFyRh9msFo0HWeW0vTL8Qv+w=="
|
||||
},
|
||||
"vue-resize": {
|
||||
"version": "0.4.5",
|
||||
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-0.4.5.tgz",
|
||||
"integrity": "sha512-bhP7MlgJQ8TIkZJXAfDf78uJO+mEI3CaLABLjv0WNzr4CcGRGPIAItyWYnP6LsPA4Oq0WE+suidNs6dgpO4RHg=="
|
||||
},
|
||||
"vue-router": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-2.7.0.tgz",
|
||||
|
||||
@ -48,6 +48,7 @@
|
||||
"toastr": "^2.1.4",
|
||||
"upgrade": "^1.1.0",
|
||||
"v-money": "^0.8.1",
|
||||
"v-tooltip": "^2.0.2",
|
||||
"vue": "^2.5.17",
|
||||
"vue-avatar-cropper": "^1.0.5",
|
||||
"vue-i18n": "^8.14.0",
|
||||
|
||||
2
public/assets/css/crater.css
vendored
2
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=af9e4f2aa907d480466c",
|
||||
"/assets/css/crater.css": "/assets/css/crater.css?id=9d83f53c3915b38417e0"
|
||||
"/assets/js/app.js": "/assets/js/app.js?id=397e57d36ef22a2e14fc",
|
||||
"/assets/css/crater.css": "/assets/css/crater.css?id=616996a79c1df69d18de"
|
||||
}
|
||||
|
||||
16
readme.md
16
readme.md
@ -14,7 +14,8 @@ Web Application is made using Laravel & VueJS while the Mobile Apps are built us
|
||||
4. [Discord](#discord)
|
||||
5. [Roadmap](#roadmap)
|
||||
6. [Credits](#credits)
|
||||
7. [License](#license)
|
||||
7. [Help us translate](#translate)
|
||||
8. [License](#license)
|
||||
|
||||
## Documentation
|
||||
|
||||
@ -28,11 +29,11 @@ Web Application is made using Laravel & VueJS while the Mobile Apps are built us
|
||||
|
||||
## Mobile Apps
|
||||
- [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)
|
||||
|
||||
## Discord
|
||||
Join the Crater discord server to discuss:
|
||||
Join the Crater discord server to discuss:
|
||||
[Invite Link](https://discord.gg/nyTstm6)
|
||||
|
||||
## Roadmap
|
||||
@ -59,6 +60,15 @@ Join the Crater discord server to discuss:
|
||||
## Credits
|
||||
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
|
||||
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
|
||||
Crater is released under the Attribution Assurance License.
|
||||
See [LICENSE](LICENSE) for details.
|
||||
|
||||
2
resources/assets/js/bootstrap.js
vendored
2
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 CategoryModal from './components/base/modal/CategoryModal.vue'
|
||||
import money from 'v-money'
|
||||
import VTooltip from 'v-tooltip'
|
||||
|
||||
/**
|
||||
* Global css plugins
|
||||
@ -107,6 +108,7 @@ window.toastr = require('toastr')
|
||||
|
||||
Vue.use(VueRouter)
|
||||
Vue.use(Vuex)
|
||||
Vue.use(VTooltip)
|
||||
|
||||
// register directive v-money and component <money>
|
||||
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 BaseLoader from './BaseLoader.vue'
|
||||
import BaseCustomerSelect from './BaseCustomerSelect.vue'
|
||||
import BasePrefixInput from './BasePrefixInput.vue'
|
||||
|
||||
import BasePopup from './popup/BasePopup.vue'
|
||||
import CustomerSelectPopup from './popup/CustomerSelectPopup.vue'
|
||||
@ -23,6 +24,7 @@ Vue.component('base-input', BaseInput)
|
||||
Vue.component('base-switch', BaseSwitch)
|
||||
Vue.component('base-text-area', BaseTextArea)
|
||||
Vue.component('base-loader', BaseLoader)
|
||||
Vue.component('base-prefix-input', BasePrefixInput)
|
||||
|
||||
Vue.component('table-component', TableComponent)
|
||||
Vue.component('table-column', TableColumn)
|
||||
|
||||
@ -21,6 +21,9 @@ import EstimateTemplate from './EstimateTemplate'
|
||||
import InvoiceTemplate from './InvoiceTemplate'
|
||||
import CustomerModal from './CustomerModal'
|
||||
import CategoryModal from './CategoryModal'
|
||||
import PaymentMode from './PaymentModeModal'
|
||||
import ItemUnit from './ItemUnitModal'
|
||||
import MailTestModal from './MailTestModal'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -29,7 +32,10 @@ export default {
|
||||
EstimateTemplate,
|
||||
InvoiceTemplate,
|
||||
CustomerModal,
|
||||
CategoryModal
|
||||
CategoryModal,
|
||||
PaymentMode,
|
||||
ItemUnit,
|
||||
MailTestModal
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
||||
@ -55,6 +55,7 @@
|
||||
v-model="currency"
|
||||
:options="currencies"
|
||||
:searchable="true"
|
||||
:allow-empty="false"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('customers.select_currency')"
|
||||
label="name"
|
||||
@ -163,15 +164,10 @@
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('customers.state') }}</label>
|
||||
<div class="col-sm-7">
|
||||
<base-select
|
||||
v-model="billingState"
|
||||
:options="billingStates"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('general.select_state')"
|
||||
:disabled="isDisabledBillingState"
|
||||
track-by="id"
|
||||
label="name"
|
||||
<base-input
|
||||
v-model="billing.state"
|
||||
type="text"
|
||||
name="billingState"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -179,29 +175,14 @@
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('customers.city') }}</label>
|
||||
<div class="col-sm-7">
|
||||
<base-select
|
||||
v-model="billingCity"
|
||||
:options="billingCities"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('general.select_city')"
|
||||
:disabled="isDisabledBillingCity"
|
||||
track-by="id"
|
||||
label="name"
|
||||
<base-input
|
||||
v-model="billing.city"
|
||||
type="text"
|
||||
name="billingCity"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Zip Code</label>
|
||||
<div class="col-sm-7">
|
||||
<base-input
|
||||
v-model="billing.zip"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('customers.zip_code') }}</label>
|
||||
<div class="col-sm-7">
|
||||
@ -294,15 +275,10 @@
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('customers.state') }}</label>
|
||||
<div class="col-sm-7">
|
||||
<base-select
|
||||
v-model="shippingState"
|
||||
:options="shippingStates"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('general.select_state')"
|
||||
:disabled="isDisabledShippingState"
|
||||
track-by="id"
|
||||
label="name"
|
||||
<base-input
|
||||
v-model="shipping.state"
|
||||
type="text"
|
||||
name="shippingState"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -310,15 +286,10 @@
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('customers.city') }}</label>
|
||||
<div class="col-sm-7">
|
||||
<base-select
|
||||
v-model="shippingCity"
|
||||
:options="shippingCities"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('general.select_city')"
|
||||
:disabled="isDisabledShippingCity"
|
||||
track-by="id"
|
||||
label="name"
|
||||
<base-input
|
||||
v-model="shipping.city"
|
||||
type="text"
|
||||
name="shippingCity"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -370,18 +341,11 @@ export default {
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
return {
|
||||
isEdit: false,
|
||||
isLoading: false,
|
||||
countryList: [],
|
||||
billingStates: [],
|
||||
billingCities: [],
|
||||
billingCountry: null,
|
||||
billingState: null,
|
||||
billingCity: null,
|
||||
shippingStates: [],
|
||||
shippingCities: [],
|
||||
shippingCountry: null,
|
||||
shippingState: null,
|
||||
shippingCity: null,
|
||||
isCopyFromBilling: false,
|
||||
currencyList: [],
|
||||
currency: '',
|
||||
@ -436,73 +400,42 @@ export default {
|
||||
...mapGetters('currency', [
|
||||
'defaultCurrency',
|
||||
'currencies'
|
||||
]),
|
||||
...mapGetters('modal', [
|
||||
'modalDataID',
|
||||
'modalData',
|
||||
'modalActive'
|
||||
])
|
||||
},
|
||||
watch: {
|
||||
'modalDataID' (val) {
|
||||
if (val) {
|
||||
this.isEdit = true
|
||||
this.setData()
|
||||
} else {
|
||||
this.isEdit = false
|
||||
}
|
||||
},
|
||||
billingCountry () {
|
||||
if (this.billingCountry) {
|
||||
this.billing.country_id = this.billingCountry.id
|
||||
this.isDisabledBillingState = false
|
||||
this.fetchBillingStates(this.billingCountry.id)
|
||||
this.billingState = null
|
||||
this.billingCity = null
|
||||
return true
|
||||
}
|
||||
},
|
||||
billingState () {
|
||||
if (this.billingState) {
|
||||
this.billing.state_id = this.billingState.id
|
||||
this.isDisabledBillingCity = false
|
||||
this.fetchBillingCities(this.billingState.id)
|
||||
this.billingCity = null
|
||||
return true
|
||||
}
|
||||
this.billingCity = null
|
||||
this.isDisabledBillingCity = true
|
||||
},
|
||||
billingCity () {
|
||||
if (this.billingCity) {
|
||||
this.billing.city_id = this.billingCity.id
|
||||
}
|
||||
},
|
||||
shippingCountry () {
|
||||
if (this.shippingCountry) {
|
||||
this.shipping.country_id = this.shippingCountry.id
|
||||
this.isDisabledShippingState = false
|
||||
this.fetchShippingStates(this.shippingCountry.id)
|
||||
if (this.isCopyFromBilling) {
|
||||
return true
|
||||
}
|
||||
this.shippingState = null
|
||||
this.shippingCity = null
|
||||
return true
|
||||
}
|
||||
},
|
||||
shippingState () {
|
||||
if (this.shippingState) {
|
||||
this.shipping.state_id = this.shippingState.id
|
||||
this.isDisabledShippingCity = false
|
||||
this.fetchShippingCities(this.shippingState.id)
|
||||
if (this.isCopyFromBilling) {
|
||||
this.isCopyFromBilling = false
|
||||
return true
|
||||
}
|
||||
this.shippingCity = null
|
||||
return true
|
||||
}
|
||||
this.shippingCity = null
|
||||
this.isDisabledShippingCity = true
|
||||
},
|
||||
shippingCity () {
|
||||
if (this.shippingCity) {
|
||||
this.shipping.city_id = this.shippingCity.id
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$refs.name.focus = true
|
||||
this.currency = this.defaultCurrency
|
||||
this.fetchCountry()
|
||||
if (this.modalDataID) {
|
||||
this.setData()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('invoice', {
|
||||
@ -529,16 +462,8 @@ export default {
|
||||
addresses: []
|
||||
}
|
||||
|
||||
this.billingStates = []
|
||||
this.billingCities = []
|
||||
this.billingCountry = null
|
||||
this.billingState = null
|
||||
this.billingCity = null
|
||||
this.shippingStates = []
|
||||
this.shippingCities = []
|
||||
this.shippingCountry = null
|
||||
this.shippingState = null
|
||||
this.shippingCity = null
|
||||
|
||||
this.billing = {...AddressStub}
|
||||
this.shipping = {...AddressStub}
|
||||
@ -553,13 +478,9 @@ export default {
|
||||
this.isCopyFromBilling = true
|
||||
this.shipping = {...this.billing, type: 'shipping'}
|
||||
this.shippingCountry = this.billingCountry
|
||||
this.shippingState = this.billingState
|
||||
this.shippingCity = this.billingCity
|
||||
} else {
|
||||
this.shipping = {...AddressStub, type: 'shipping'}
|
||||
this.shippingCountry = null
|
||||
this.shippingState = null
|
||||
this.shippingCity = null
|
||||
}
|
||||
},
|
||||
async loadData () {
|
||||
@ -589,6 +510,24 @@ export default {
|
||||
this.formData.addresses = [{...this.shipping, type: 'shipping'}]
|
||||
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 () {
|
||||
this.$v.formData.$touch()
|
||||
|
||||
@ -606,14 +545,23 @@ export default {
|
||||
this.formData.currency_id = this.defaultCurrency.id
|
||||
}
|
||||
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) {
|
||||
window.toastr['success'](this.$tc('customers.created_message'))
|
||||
if (this.modalDataID) {
|
||||
window.toastr['success'](this.$tc('customers.updated_message'))
|
||||
} else {
|
||||
window.toastr['success'](this.$tc('customers.created_message'))
|
||||
}
|
||||
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)
|
||||
}
|
||||
if (this.$route.name === 'estimates.create') {
|
||||
if (this.$route.name === 'estimates.create' || this.$route.name === 'estimates.edit') {
|
||||
this.setEstimateCustomer(response.data.customer.id)
|
||||
}
|
||||
this.resetData()
|
||||
@ -633,30 +581,6 @@ export default {
|
||||
if (res) {
|
||||
this.countryList = res.data.countries
|
||||
}
|
||||
},
|
||||
async fetchBillingStates (id) {
|
||||
let res = await window.axios.get(`/api/states/${id}`)
|
||||
if (res) {
|
||||
this.billingStates = res.data.states
|
||||
}
|
||||
},
|
||||
async fetchBillingCities (id) {
|
||||
let res = await window.axios.get(`/api/cities/${id}`)
|
||||
if (res) {
|
||||
this.billingCities = res.data.cities
|
||||
}
|
||||
},
|
||||
async fetchShippingStates (id) {
|
||||
let res = await window.axios.get(`/api/states/${id}`)
|
||||
if (res) {
|
||||
this.shippingStates = res.data.states
|
||||
}
|
||||
},
|
||||
async fetchShippingCities (id) {
|
||||
let res = await window.axios.get(`/api/cities/${id}`)
|
||||
if (res) {
|
||||
this.shippingCities = res.data.cities
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,14 +45,34 @@
|
||||
<div class="col-sm-7">
|
||||
<base-select
|
||||
v-model="formData.unit"
|
||||
:options="units"
|
||||
:options="itemUnits"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
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 class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('items.description') }}</label>
|
||||
<div class="col-sm-7">
|
||||
@ -124,11 +144,13 @@ export default {
|
||||
{ name: 'mg', value: 'mg' },
|
||||
{ name: 'pc', value: 'pc' }
|
||||
],
|
||||
taxes: [],
|
||||
formData: {
|
||||
name: null,
|
||||
price: null,
|
||||
description: null,
|
||||
unit: null
|
||||
unit: null,
|
||||
taxes: []
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -161,12 +183,28 @@ export default {
|
||||
this.formData.price = newValue * 100
|
||||
}
|
||||
},
|
||||
// itemUnits () {
|
||||
// return this.units
|
||||
// },
|
||||
...mapGetters('modal', [
|
||||
'modalDataID'
|
||||
'modalDataID',
|
||||
'modalData'
|
||||
]),
|
||||
...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: {
|
||||
modalDataID () {
|
||||
@ -179,12 +217,17 @@ export default {
|
||||
this.isEdit = true
|
||||
this.fetchEditData()
|
||||
}
|
||||
|
||||
if (this.isEdit) {
|
||||
this.loadEditData()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$refs.name.focus = true
|
||||
},
|
||||
methods: {
|
||||
...mapActions('modal', [
|
||||
'openModal',
|
||||
'closeModal',
|
||||
'resetModalData'
|
||||
]),
|
||||
@ -203,7 +246,6 @@ export default {
|
||||
unit: null,
|
||||
id: null
|
||||
}
|
||||
|
||||
this.$v.$reset()
|
||||
},
|
||||
fetchEditData () {
|
||||
@ -230,9 +272,20 @@ export default {
|
||||
if (this.isEdit) {
|
||||
response = await this.updateItem(this.formData)
|
||||
} 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) {
|
||||
window.toastr['success'](this.$tc('items.created_message'))
|
||||
this.setItem(response.data.item)
|
||||
@ -245,6 +298,12 @@ export default {
|
||||
}
|
||||
window.toastr['error'](response.data.error)
|
||||
},
|
||||
async addItemUnit () {
|
||||
this.openModal({
|
||||
'title': 'Add Item Unit',
|
||||
'componentName': 'ItemUnit'
|
||||
})
|
||||
},
|
||||
closeItemModal () {
|
||||
this.resetFormData()
|
||||
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>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user