Compare commits

...

97 Commits
3.0.0 ... 3.1.0

Author SHA1 Message Date
2b03bc798e new build 310 2020-05-21 11:26:26 +05:30
482556d378 Merge branch 'resend-email' into 'master'
Add Resend Email Option

See merge request mohit.panjvani/crater-web!236
2020-05-21 05:51:36 +00:00
deb525af6e build 310 2020-05-19 13:22:33 +05:30
cb2bfbb91c Add steps for update app 2020-05-19 07:50:58 +00:00
654395a175 Add steps for update app 2020-05-19 07:50:58 +00:00
e31b60bc48 Refactor Self Update Endpoints and Add Update Console Command 2020-05-17 07:04:43 +00:00
183953f4c4 Refactor Self Update Endpoints and Add Update Console Command 2020-05-17 07:04:43 +00:00
a24d8d3ebc fix updater issue 2020-05-13 16:50:45 +05:30
4ca574c581 fix migration errors 2020-05-13 12:47:06 +05:30
c7ce8c87dd new build 2020-05-13 11:31:37 +05:30
f64d546672 refactor 310 update listener 2020-05-13 11:12:33 +05:30
d4a1f1a784 fix item selection and item loader 2020-05-12 13:23:06 +05:30
e07532961e reset items on selection 2020-05-12 13:11:29 +05:30
450c265ded Merge branch 'refactor-report-pdfs' into 'master'
Refactor report pdfs

See merge request mohit.panjvani/crater-web!233
2020-05-11 15:48:49 +00:00
f8502c3ca8 Merge branch 'customer-delete' into 'master'
Customer delete label

See merge request mohit.panjvani/crater-web!237
2020-05-11 15:47:33 +00:00
899da6990d Merge branch 'new-issues' into 'master'
New issues

See merge request mohit.panjvani/crater-web!239
2020-05-11 15:47:03 +00:00
e7675f938e refactor estimate to invoice endpoint 2020-05-11 19:05:50 +05:30
b08138e9e0 refactor estimate to invoice endpoint 2020-05-11 18:34:20 +05:30
5df4abdc4b add aws-sdk-php package 2020-05-11 18:15:36 +05:30
a2fa8afa72 fix translation issue 2020-05-11 18:09:34 +05:30
7670cd67dc Merge branch 'template-refactor' into 'master'
refactor invoice2

See merge request mohit.panjvani/crater-web!238
2020-05-11 12:24:22 +00:00
8446ac2b27 refactor invoice2 2020-05-11 16:19:02 +05:30
63a80e44d5 Customer delete label 2020-05-11 14:33:11 +05:30
076df75322 Merge branch 'template-refactor' into 'master'
Template refactor

See merge request mohit.panjvani/crater-web!232
2020-05-11 07:03:45 +00:00
11db99da73 refactor invoice 1 style 2020-05-09 18:50:58 +05:30
050dca5a50 Add copy pdf url option 2020-05-09 14:37:22 +05:30
3c096f1386 Add Resend Email Option 2020-05-09 14:22:13 +05:30
0f3e8fce3b refactor heading text in payment 2020-05-08 20:55:00 +05:30
325f90bba5 Fix issues on invoice template 2020-05-08 18:49:02 +05:30
a739a938fc Fix estimate template issues 2020-05-08 16:52:48 +05:30
b30e3a9b11 merge with github 2020-05-08 11:11:57 +05:30
fc1a7c7438 refactor reports pdfs 2020-05-07 18:59:50 +05:30
6046113cb1 Refactor Invoice and Payment templates 2020-05-07 16:42:04 +05:30
611ffafec5 refactor sales customers pdf 2020-05-06 20:41:15 +05:30
c497b906df refactor taxt report pdf 2020-05-06 20:32:10 +05:30
c68fce19f9 refactor expenses pdf 2020-05-06 19:02:02 +05:30
f8913531b6 refactor profit loss pdfs 2020-05-06 18:09:28 +05:30
30f76e2088 Refactor Estimate templates 2020-05-06 18:02:27 +05:30
39556892cd refactor sales customers 2020-05-05 20:58:20 +05:30
2fd66bf748 refactor sales items and customer pdfs 2020-05-05 20:49:51 +05:30
d4f1428d5f refactor sales customers pdf template 2020-05-05 20:03:51 +05:30
189141c84d Refactor estimate pdf template 2020-05-05 18:21:25 +05:30
f8ccfece09 update templates 2020-05-05 13:12:26 +05:30
9a7c926d53 fix 310 update issues 2020-05-02 18:53:51 +05:30
c5c1674153 Merge branch 'master' 2020-05-02 13:37:36 +05:30
8562ee5414 Merge branch 'settings-customization-payments' into 'master'
Payments and UnitItems in doubles issue fixed...

See merge request mohit.panjvani/crater-web!218
2020-04-27 16:09:25 +00:00
06c66a756c Payments and UnitItems in doubles issue fixed... 2020-04-27 18:54:24 +05:30
b66d07d21b Merge pull request #201 from rexlManu/master
Updated German Language
2020-04-27 12:14:23 +05:30
05001b6a79 Merge pull request #170 from RobinDev/patch-1
Update french language
2020-04-21 14:52:02 +05:30
f02f4ba9d3 Updated German Language 2020-04-21 07:31:33 +02:00
fbace98aac add missing translation 2020-04-20 21:12:03 +02:00
8f0af3dcd6 Merge branch 'master' of https://github.com/bytefury/crater 2020-04-20 11:23:00 +05:30
e8e44c5dc8 Merge pull request #180 from alessandrofuda/master
IT Italian translation
2020-04-18 13:38:21 +05:30
ac33164342 Merge branch '3.1.0' into 'master'
add listener 310

See merge request mohit.panjvani/crater-web!202
2020-04-18 07:29:08 +00:00
5c7c0d84ea Merge branch 'refactor-crater-3.0.0' into 'master'
Refactor line-chart

See merge request mohit.panjvani/crater-web!203
2020-04-18 07:15:52 +00:00
7ca725ac37 refactor line-chart 2020-04-17 19:53:08 +05:30
510a4b3dbb add listener 310 2020-04-17 19:05:10 +05:30
0f130ab1b8 Update fr langugage 2020-04-17 09:57:38 +02:00
25114009e3 remove unused components and update eslint + prettier config 2020-03-30 11:40:45 +05:30
79c16d74ce IT Italian translation 2020-03-20 18:18:27 +01:00
742e1e445a Merge branch 'expense-refactor' into 'master'
add customer in expense

See merge request mohit.panjvani/crater-web!172
2020-03-20 07:12:39 +00:00
386f96d60e Merge branch 'version301' into 'master'
add new minor version update 3.0.1

See merge request mohit.panjvani/crater-web!169
2020-03-20 07:12:27 +00:00
82d85af672 refactor and merge backend 2020-03-18 18:21:53 +05:30
4d1b267688 Merge branch 'expense-refactor' of https://gitlab.com/mohit.panjvani/crater-web into expense-refactor 2020-03-18 17:41:15 +05:30
bc99ad63a6 add user to expense 2020-03-18 17:40:03 +05:30
4bb44f8c93 add customer filter on index 2020-03-18 17:19:09 +05:30
c72265ed50 add languages 2020-03-17 19:38:59 +05:30
b8958c9eb6 add customer in expense 2020-03-17 19:20:42 +05:30
e33e314cb7 new frontend build 2020-03-09 15:20:59 +05:30
84cebee9da Merge branch 'master' of https://github.com/bytefury/crater 2020-03-09 15:19:54 +05:30
34d3cf7ae8 Merge branch 'item-refactor' into 'master'
refactor item search problem

See merge request mohit.panjvani/crater-web!171
2020-03-09 09:49:26 +00:00
93d0da836a Merge pull request #172 from digitalsign/master
Change project name in composer.json
2020-02-26 14:35:21 +05:30
fd51276948 Change project name in composer.json 2020-02-26 13:31:57 +08:00
d6274854ba refactor search problem 2020-02-19 19:10:43 +05:30
ea4bd1a31d Merge pull request #154 from lukasmu/bugfix/expenses-note
Fixed small bug that might occur when an expense is updated
2020-02-09 12:01:43 +05:30
286e047963 Merge pull request #129 from deanhouseholder/master
Detect if no .env file exists and add it on composer commands.
2020-02-09 12:01:25 +05:30
be16f48f3d Merge pull request #153 from MakerLab-Dev/patch-3
Improved error handling
2020-02-09 12:00:23 +05:30
ebea1e0813 add new minor version update 3.0.1 2020-02-07 17:20:32 +05:30
cc8d08f829 Merge pull request #142 from miraro3/master
Added Kyrgyzstani som
2020-02-07 16:42:15 +05:30
aacffc22eb fix merge conflict 2020-02-03 21:15:07 +05:30
d71ca4ffb9 Fixed small bug that might occur when an expense is updated
Previoulsy a string with contents "null" is transmitted and saved to the database when updating an expense with an empty note. This fix prevents that.
Please note that this fix still needs to be compiled with npm.
2020-02-01 14:52:07 +01:00
186004f7f8 fix merge conflicts 2020-01-31 14:28:16 +05:30
c2eb22d666 Merge pull request #137 from MakerLab-Dev/patch-1
cross-env should only be in devDependencies
2020-01-31 01:26:32 +05:30
af189b15b6 Small fix 2020-01-30 20:48:16 +01:00
1c19be85c3 Improved error handling 2020-01-30 20:47:51 +01:00
4bb4362d23 Removed unnecessary notification
Removed unnecessary notification as the improved error handler will show it
2020-01-30 20:45:39 +01:00
f6f66b3ae6 Merge pull request #152 from mdpoulter/email-subject
More descriptive email fields.
2020-01-31 00:21:29 +05:30
b4ccecbcf1 Merge pull request #149 from proea/master
Fix for "Empty PDF rendered in Docker #69"
2020-01-31 00:11:51 +05:30
92f1f196bb Update Dockerfile 2020-01-27 22:38:47 +03:00
ee14070a7b Update Dockerfile
slight change
2020-01-27 22:37:41 +03:00
8ce7e14a02 Add name in From field. 2020-01-27 20:37:25 +02:00
3401ca049e Make viewed emails more descriptive. 2020-01-27 14:47:02 +02:00
5dcc7b9efd Add more descriptive subject lines. 2020-01-27 14:45:40 +02:00
406d098172 Update Dockerfile
Generation does not work due to:
iconv(): Wrong charset, conversion from `UTF-8' to `UTF-8//IGNORE' is not allowed

Installing the library gnu-libiconv will solve the problem
2020-01-26 23:18:15 +03:00
f68e86e4cf Added Kyrgyzstani som 2020-01-20 22:37:03 +01:00
0990ce4678 cross-env should only be in devDependencies 2020-01-18 16:29:48 +01:00
353c2479f1 Detect if no .env file exists and add it on composer commands. 2020-01-06 10:55:34 -07:00
94 changed files with 7420 additions and 10442 deletions

View File

@ -2,9 +2,17 @@
"root": true,
"extends": [
"plugin:vue/recommended",
"standard"
"eslint:recommended",
"prettier/vue",
"plugin:prettier/recommended"
],
"rules": {
"vue/max-attributes-per-line" : 3
"vue/max-attributes-per-line": ["error", {
"singleline": 10,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}]
}
}

5
.prettierrc.json Normal file
View File

@ -0,0 +1,5 @@
{
"semi": false,
"singleQuote": true,
"tabWidth": 2
}

View File

@ -23,9 +23,11 @@ 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 && \
RUN apk add --no-cache libpng-dev libxml2-dev oniguruma-dev libzip-dev gnu-libiconv && \
docker-php-ext-install bcmath ctype json gd mbstring pdo pdo_mysql tokenizer xml zip
ENV LD_PRELOAD /usr/lib/preloadable_libiconv.so php
# Set container's working dir
WORKDIR /app
@ -49,4 +51,3 @@ RUN touch database/database.sqlite && \
EXPOSE 9000
CMD ["php-fpm", "--nodaemonize"]

View File

@ -0,0 +1,189 @@
<?php
namespace Crater\Console\Commands;
use Illuminate\Console\Command;
use Crater\Space\Updater;
use Crater\Setting;
class UpdateCommand extends Command
{
public $installed;
public $version;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'crater:update';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Automatically update your crater app';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*/
public function handle()
{
set_time_limit(3600); // 1 hour
$this->installed = $this->getInstalledVersion();
$this->version = $this->getLatestVersion();
if (!$this->version) {
$this->info('No Update Available! You are already on the latest version.');
return;
}
if (!$this->confirm("Do you wish to update to {$this->version}?")) {
return;
}
if (!$path = $this->download()) {
return;
}
if (!$path = $this->unzip($path)) {
return;
}
if (!$this->copyFiles($path)) {
return;
}
if (!$this->migrateUpdate()) {
return;
}
if (!$this->finish()) {
return;
}
$this->info('Successfully updated to ' . $this->version);
}
public function getInstalledVersion()
{
return Setting::getSetting('version');
}
public function getLatestVersion()
{
$this->info('Your currently installed version is ' . $this->installed);
$this->line('');
$this->info('Checking for update...');
try {
$response = Updater::checkForUpdate($this->installed);
if ($response->success) {
return $response->version->version;
}
return false;
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
}
public function download()
{
$this->info('Downloading update...');
try {
$path = Updater::download($this->version);
if (!is_string($path)) {
$this->error('Download exception');
return false;
}
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return $path;
}
public function unzip($path)
{
$this->info('Unzipping update package...');
try {
$path = Updater::unzip($path);
if (!is_string($path)) {
$this->error('Unzipping exception');
return false;
}
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return $path;
}
public function copyFiles($path)
{
$this->info('Copying update files...');
try {
Updater::copyFiles($path);
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return true;
}
public function migrateUpdate()
{
$this->info('Running Migrations...');
try {
Updater::migrateUpdate();
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return true;
}
public function finish()
{
$this->info('Finishing update...');
try {
Updater::finishUpdate($this->installed, $this->version);
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return true;
}
}

View File

@ -12,7 +12,8 @@ class Kernel extends ConsoleKernel
* @var array
*/
protected $commands = [
Commands\ResetApp::class
Commands\ResetApp::class,
Commands\UpdateCommand::class
];
/**

View File

@ -5,6 +5,7 @@ use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia\HasMedia;
use Spatie\MediaLibrary\HasMedia\HasMediaTrait;
use Crater\ExpenseCategory;
use Crater\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
@ -16,6 +17,7 @@ class Expense extends Model implements HasMedia
'expense_category_id',
'amount',
'company_id',
'user_id',
'expense_date',
'notes',
'attachment_receipt'
@ -32,6 +34,11 @@ class Expense extends Model implements HasMedia
return $this->belongsTo(ExpenseCategory::class, 'expense_category_id');
}
public function user()
{
return $this->belongsTo(User::class);
}
public function getFormattedExpenseDateAttribute($value)
{
$dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id);
@ -81,6 +88,11 @@ class Expense extends Model implements HasMedia
return $query->where('expenses.expense_category_id', $categoryId);
}
public function scopeWhereUser($query, $user_id)
{
return $query->where('expenses.user_id', $user_id);
}
public function scopeApplyFilters($query, array $filters)
{
$filters = collect($filters);
@ -89,6 +101,10 @@ class Expense extends Model implements HasMedia
$query->whereCategory($filters->get('expense_category_id'));
}
if ($filters->get('user_id')) {
$query->whereUser($filters->get('user_id'));
}
if ($filters->get('from_date') && $filters->get('to_date')) {
$start = Carbon::createFromFormat('d/m/Y', $filters->get('from_date'));
$end = Carbon::createFromFormat('d/m/Y', $filters->get('to_date'));

View File

@ -143,13 +143,14 @@ class CompanyController extends Controller
$currency = CompanySetting::getSetting('currency', $request->header('company'));
$fiscal_year = CompanySetting::getSetting('fiscal_year', $request->header('company'));
$languages = [
$languages = [ // alphabetical order
["code"=>"pt_BR", "name" => "Brazilian Portuguese"],
["code"=>"en", "name" => "English"],
["code"=>"fr", "name" => "French"],
["code"=>"de", "name" => "German"],
["code"=>"it", "name" => "Italian"],
["code"=>"es", "name" => "Spanish"],
["code"=>"ar", "name" => "العربية"],
["code"=>"de", "name" => "German"],
["code"=>"pt_BR", "name" => "Brazilian Portuguese"],
];
return response()->json([

View File

@ -175,12 +175,6 @@ class EstimatesController extends Controller
]);
}
if (!config('mail.from.name')) {
return response()->json([
'error' => 'from_email_does_not_exist'
]);
}
\Mail::to($email)->send(new EstimatePdf($data));
}
@ -343,12 +337,6 @@ class EstimatesController extends Controller
]);
}
if (!config('mail.from.name')) {
return response()->json([
'error' => 'from_email_does_not_exist'
]);
}
\Mail::to($email)->send(new EstimatePdf($data));
if ($estimate->status == Estimate::STATUS_DRAFT) {
@ -397,12 +385,12 @@ class EstimatesController extends Controller
public function estimateToInvoice(Request $request, $id)
{
$estimate = Estimate::with(['items', 'items.taxes', 'user', 'estimateTemplate', 'taxes'])->find($id);
$invoice_date = Carbon::parse($estimate->estimate_date);
$invoice_date = Carbon::now();
$invoice_prefix = CompanySetting::getSetting(
'invoice_prefix',
$request->header('company')
);
$due_date = Carbon::parse($estimate->estimate_date)->addDays(7);
$due_date = Carbon::now()->addDays(7);
$tax_per_item = CompanySetting::getSetting(
'tax_per_item',
$request->header('company')

View File

@ -1,4 +1,5 @@
<?php
namespace Crater\Http\Controllers;
use Crater\Expense;
@ -24,9 +25,11 @@ class ExpensesController extends Controller
$limit = $request->has('limit') ? $request->limit : 10;
$expenses = Expense::with('category')
->leftJoin('users', 'users.id', '=', 'expenses.user_id')
->join('expense_categories', 'expense_categories.id', '=', 'expenses.expense_category_id')
->applyFilters($request->only([
'expense_category_id',
'user_id',
'search',
'from_date',
'to_date',
@ -34,11 +37,16 @@ class ExpensesController extends Controller
'orderBy'
]))
->whereCompany($request->header('company'))
->select('expenses.*', 'expense_categories.name')
->select('expenses.*', 'expense_categories.name', 'users.name as user_name')
->paginate($limit);
$customers = User::customer()
->whereCompany($request->header('company'))
->get();
return response()->json([
'expenses' => $expenses,
'customers' => $customers,
'currency' => Currency::findOrFail(
CompanySetting::getSetting('currency', $request->header('company'))
)
@ -53,9 +61,13 @@ class ExpensesController extends Controller
public function create(Request $request)
{
$categories = ExpenseCategory::whereCompany($request->header('company'))->get();
$customers = User::customer()
->whereCompany($request->header('company'))
->get();
return response()->json([
'categories' => $categories
'categories' => $categories,
'customers' => $customers
]);
}
@ -72,6 +84,7 @@ class ExpensesController extends Controller
$expense = new Expense();
$expense->notes = $request->notes;
$expense->expense_category_id = $request->expense_category_id;
$expense->user_id = $request->user_id;
$expense->amount = $request->amount;
$expense->company_id = $request->header('company');
$expense->expense_date = $expense_date;
@ -104,10 +117,12 @@ class ExpensesController extends Controller
* @param $id
* @return \Illuminate\Http\JsonResponse
*/
public function edit(Request $request,$id)
public function edit(Request $request, $id)
{
$categories = ExpenseCategory::whereCompany($request->header('company'))->get();
$customers = User::where('role', 'customer')->whereCompany($request->header('company'))->get();
$customers = User::customer()
->whereCompany($request->header('company'))
->get();
$expense = Expense::with('category')->where('id', $id)->first();
return response()->json([
@ -132,6 +147,7 @@ class ExpensesController extends Controller
$expense->notes = $request->notes;
$expense->expense_category_id = $request->expense_category_id;
$expense->amount = $request->amount;
$expense->user_id = $request->user_id;
$expense->expense_date = $expense_date;
$expense->save();
@ -181,11 +197,11 @@ class ExpensesController extends Controller
{
$data = json_decode($request->attachment_receipt);
if($data) {
if ($data) {
$expense = Expense::find($id);
if($expense) {
if($request->type === 'edit') {
if ($expense) {
if ($request->type === 'edit') {
$expense->clearMediaCollection('receipts');
}
@ -211,9 +227,9 @@ class ExpensesController extends Controller
$expense = Expense::find($id);
$imagePath = null;
if($expense) {
if ($expense) {
$media = $expense->getFirstMedia('receipts');
if($media) {
if ($media) {
$imagePath = $media->getPath();
} else {
return response()->json([
@ -224,7 +240,7 @@ class ExpensesController extends Controller
$type = \File::mimeType($imagePath);
$image = 'data:'.$type.';base64,'.base64_encode(file_get_contents($imagePath));
$image = 'data:' . $type . ';base64,' . base64_encode(file_get_contents($imagePath));
return response()->json([
'image' => $image,
@ -249,17 +265,10 @@ class ExpensesController extends Controller
->first();
$imagePath = null;
if($expense) {
if ($expense) {
$media = $expense->getFirstMedia('receipts');
if($media) {
if ($media) {
$imagePath = $media->getPath();
$filename = $media->getPath();
$type = \File::mimeType($imagePath);
$headers = array(
'Content-Type' => $type,
);
$response = \Response::download($imagePath, $media->file_name);
ob_end_clean();
return $response;
@ -271,4 +280,3 @@ class ExpensesController extends Controller
]);
}
}

View File

@ -12,7 +12,7 @@ use Crater\Invoice;
use Crater\InvoiceItem;
use Carbon\Carbon;
use Crater\Item;
use Crater\Mail\invoicePdf;
use Crater\Mail\InvoicePdf;
use function MongoDB\BSON\toJSON;
use Illuminate\Support\Facades\Log;
use Crater\User;
@ -175,13 +175,7 @@ class InvoicesController extends Controller
]);
}
if (!config('mail.from.name')) {
return response()->json([
'error' => 'from_email_does_not_exist'
]);
}
\Mail::to($email)->send(new invoicePdf($data));
\Mail::to($email)->send(new InvoicePdf($data));
}
$invoice = Invoice::with(['items', 'user', 'invoiceTemplate', 'taxes'])->find($invoice->id);
@ -410,13 +404,7 @@ class InvoicesController extends Controller
]);
}
if (!config('mail.from.name')) {
return response()->json([
'error' => 'from_email_does_not_exist'
]);
}
\Mail::to($email)->send(new invoicePdf($data));
\Mail::to($email)->send(new InvoicePdf($data));
if ($invoice->status == Invoice::STATUS_DRAFT) {
$invoice->status = Invoice::STATUS_SENT;

View File

@ -50,7 +50,8 @@ class OnboardingController extends Controller
["code"=>"es", "name" => "Spanish"],
["code"=>"ar", "name" => "العربية"],
["code"=>"de", "name" => "German"],
["code"=>"pt-br", "name" => "Portuguese (Brazilian)"]
["code"=>"pt-br", "name" => "Portuguese (Brazilian)"],
["code"=>"it", "name" => "Italian"],
];
$fiscal_years = [
['key' => 'january-december' , 'value' => '1-12'],

View File

@ -305,10 +305,6 @@ class PaymentController extends Controller
$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([
@ -316,13 +312,7 @@ class PaymentController extends Controller
]);
}
if (!$notificationEmail) {
return response()->json([
'error' => 'notification_email_does_not_exist'
]);
}
\Mail::to($email)->send(new PaymentPdf($data, $notificationEmail));
\Mail::to($email)->send(new PaymentPdf($data));
return response()->json([
'success' => true

View File

@ -2,23 +2,81 @@
namespace Crater\Http\Controllers;
use Crater\Setting;
use Illuminate\Http\Request;
use Crater\Space\Updater;
use Crater\Space\SiteApi;
use Illuminate\Support\Facades\Artisan;
class UpdateController extends Controller
{
public function update(Request $request)
public function download(Request $request)
{
set_time_limit(600); // 10 minutes
$request->validate([
'version' => 'required',
]);
$json = Updater::update($request->installed, $request->version);
$path = Updater::download($request->version);
return response()->json($json);
return response()->json([
'success' => true,
'path' => $path
]);
}
public function unzip(Request $request)
{
$request->validate([
'path' => 'required',
]);
try {
$path = Updater::unzip($request->path);
return response()->json([
'success' => true,
'path' => $path
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'error' => $e->getMessage()
], 500);
}
}
public function copyFiles(Request $request)
{
$request->validate([
'path' => 'required',
]);
$path = Updater::copyFiles($request->path);
return response()->json([
'success' => true,
'path' => $path
]);
}
public function migrate(Request $request)
{
Updater::migrateUpdate();
return response()->json([
'success' => true
]);
}
public function finishUpdate(Request $request)
{
$request->validate([
'installed' => 'required',
'version' => 'required',
]);
$json = Updater::finishUpdate($request->installed, $request->version);
return response()->json($json);
@ -28,7 +86,7 @@ class UpdateController extends Controller
{
set_time_limit(600); // 10 minutes
$json = Updater::checkForUpdate();
$json = Updater::checkForUpdate(Setting::getSetting('version'));
return response()->json($json);
}

View File

@ -0,0 +1,52 @@
<?php
namespace Crater\Listeners\Updates\v3;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Crater\Listeners\Updates\Listener;
use Illuminate\Database\Schema\Blueprint;
use Crater\Events\UpdateFinished;
use Crater\Setting;
use Crater\Currency;
use Schema;
use Artisan;
class Version310 extends Listener
{
const VERSION = '3.1.0';
/**
* Handle the event.
*
* @param UpdateFinished $event
* @return void
*/
public function handle(UpdateFinished $event)
{
if ($this->isListenerFired($event)) {
return;
}
Currency::firstOrCreate(
[
'name' => 'Kyrgyzstani som',
'code' => 'KGS'
],
[
'name' => 'Kyrgyzstani som',
'code' => 'KGS',
'symbol' => 'С̲ ',
'precision' => '2',
'thousand_separator' => '.',
'decimal_separator' => ','
]
);
Artisan::call('migrate', ['--force' => true]);
// Update Crater app version
Setting::setSetting('version', static::VERSION);
}
}

View File

@ -29,6 +29,9 @@ class EstimatePdf extends Mailable
*/
public function build()
{
return $this->markdown('emails.send.estimate', ['data', $this->data]);
$company = $this->data['company']['name'];
return $this->subject("Estimate from $company")
->markdown('emails.send.estimate', ['data', $this->data]);
}
}

View File

@ -31,6 +31,8 @@ class EstimateViewed extends Mailable
public function build()
{
$email = $this->data['user']['email'];
return $this->from($email)->markdown('emails.viewed.estimate', ['data', $this->data]);
$name = $this->data['user']['name'];
return $this->from($email, $name)
->markdown('emails.viewed.estimate', ['data', $this->data]);
}
}

View File

@ -6,7 +6,7 @@ use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class invoicePdf extends Mailable
class InvoicePdf extends Mailable
{
use Queueable, SerializesModels;
@ -29,6 +29,9 @@ class invoicePdf extends Mailable
*/
public function build()
{
return $this->markdown('emails.send.invoice', ['data', $this->data]);
$company = $this->data['company']['name'];
return $this->subject("Invoice from $company")
->markdown('emails.send.invoice', ['data', $this->data]);
}
}

View File

@ -31,6 +31,8 @@ class InvoiceViewed extends Mailable
public function build()
{
$email = $this->data['user']['email'];
return $this->from($email)->markdown('emails.viewed.invoice', ['data', $this->data]);
$name = $this->data['user']['name'];
return $this->from($email, $name)
->markdown('emails.viewed.invoice', ['data', $this->data]);
}
}

View File

@ -13,17 +13,14 @@ class PaymentPdf 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;
}
/**
@ -33,6 +30,9 @@ class PaymentPdf extends Mailable
*/
public function build()
{
return $this->from($this->notificationEmail)->markdown('emails.send.payment', ['data', $this->data]);
$company = $this->data['company']['name'];
return $this->subject("Payment from $company")
->markdown('emails.send.payment', ['data', $this->data]);
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace Crater\Providers;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
@ -11,6 +12,7 @@ use Crater\Listeners\Updates\v2\Version201;
use Crater\Listeners\Updates\v2\Version202;
use Crater\Listeners\Updates\v2\Version210;
use Crater\Listeners\Updates\v3\Version300;
use Crater\Listeners\Updates\v3\Version310;
class EventServiceProvider extends ServiceProvider
{
@ -20,13 +22,14 @@ class EventServiceProvider extends ServiceProvider
* @var array
*/
protected $listen = [
UpdateFinished::class=> [
UpdateFinished::class => [
Version110::class,
Version200::class,
Version201::class,
Version202::class,
Version210::class,
Version300::class,
Version310::class,
],
Registered::class => [
SendEmailVerificationNotification::class,

View File

@ -2,31 +2,45 @@
namespace Crater\Space;
use File;
use ZipArchive;
use Artisan;
use GuzzleHttp\Exception\RequestException;
use Crater\Space\SiteApi;
use Crater\Events\UpdateFinished;
use Crater\Setting;
use Illuminate\Http\Request;
use ZipArchive;
class Updater
{
use SiteApi;
public static function update($installed, $version)
public static function checkForUpdate($installed_version)
{
$data = null;
if(env('APP_ENV') === 'development')
{
$url = 'https://craterapp.com/downloads/check/latest/'. $installed_version . '?type=update&is_dev=1';
} else {
$url = 'https://craterapp.com/downloads/check/latest/'. $installed_version . '?type=update';
}
$response = static::getRemote($url, ['timeout' => 100, 'track_redirects' => true]);
if ($response && ($response->getStatusCode() == 200)) {
$data = $response->getBody()->getContents();
}
return json_decode($data);
}
public static function download($new_version)
{
$data = null;
$path = null;
if(env('APP_ENV') === 'development')
{
$url = 'https://craterapp.com/downloads/file/'.$version.'?type=update&is_dev=1';
if (env('APP_ENV') === 'development') {
$url = 'https://craterapp.com/downloads/file/' . $new_version . '?type=update&is_dev=1';
} else {
$url = 'https://craterapp.com/downloads/file/'.$version.'?type=update';
$url = 'https://craterapp.com/downloads/file/' . $new_version . '?type=update';
}
$response = static::getRemote($url, ['timeout' => 100, 'track_redirects' => true]);
// Exception
@ -45,66 +59,68 @@ class Updater
}
// Create temp directory
$path = 'temp-' . md5(mt_rand());
$path2 = 'temp2-' . md5(mt_rand());
$temp_path = storage_path('app') . '/' . $path;
$temp_path2 = storage_path('app') . '/' . $path2;
$temp_dir = storage_path('app/temp-' . md5(mt_rand()));
if (!File::isDirectory($temp_path)) {
File::makeDirectory($temp_path);
File::makeDirectory($temp_path2);
if (!File::isDirectory($temp_dir)) {
File::makeDirectory($temp_dir);
}
try {
$file = $temp_path . '/upload.zip';
$zip_file_path = $temp_dir . '/upload.zip';
// Add content to the Zip file
$uploaded = is_int(file_put_contents($file, $data)) ? true : false;
$uploaded = is_int(file_put_contents($zip_file_path, $data)) ? true : false;
if (!$uploaded) {
return false;
}
return $zip_file_path;
}
public static function unzip($zip_file_path)
{
if(!file_exists($zip_file_path)) {
throw new \Exception('Zip file not found');
}
$temp_extract_dir = storage_path('app/temp2-' . md5(mt_rand()));
if (!File::isDirectory($temp_extract_dir)) {
File::makeDirectory($temp_extract_dir);
}
// Unzip the file
$zip = new ZipArchive();
if ($zip->open($file)) {
$zip->extractTo($temp_path2);
if ($zip->open($zip_file_path)) {
$zip->extractTo($temp_extract_dir);
}
$zip->close();
// Delete zip file
File::delete($file);
File::delete($zip_file_path);
if (!File::copyDirectory($temp_path2.'/Crater', base_path())) {
return $temp_extract_dir;
}
public static function copyFiles($temp_extract_dir)
{
if (!File::copyDirectory($temp_extract_dir . '/Crater', base_path())) {
return false;
}
// Delete temp directory
File::deleteDirectory($temp_path);
File::deleteDirectory($temp_path2);
File::deleteDirectory($temp_extract_dir);
return [
'success' => true,
'error' => false,
'data' => []
];
} catch (\Exception $e) {
if (File::isDirectory($temp_path)) {
// Delete temp directory
File::deleteDirectory($temp_path);
File::deleteDirectory($temp_path2);
return true;
}
return [
'success' => false,
'error' => 'Update error',
'data' => []
];
}
public static function migrateUpdate()
{
Artisan::call('migrate --force');
return true;
}
public static function finishUpdate($installed, $version)
@ -118,22 +134,4 @@ class Updater
];
}
public static function checkForUpdate()
{
$data = null;
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]);
if ($response && ($response->getStatusCode() == 200)) {
$data = $response->getBody()->getContents();
}
return json_decode($data);
}
}

View File

@ -9,6 +9,7 @@ use carbon\carbon;
use Crater\MemberLoan;
use Crater\Address;
use Crater\Payment;
use Crater\Expense;
use Crater\Company;
use Crater\Notifications\MailResetPasswordNotification;
use Spatie\MediaLibrary\HasMedia\HasMedia;
@ -105,6 +106,11 @@ class User extends Authenticatable implements HasMedia
return $this->hasMany(Address::class);
}
public function expenses()
{
return $this->hasMany(Expense::class);
}
public function billingAddress()
{
return $this->hasOne(Address::class)->where('type', Address::BILLING_TYPE);

View File

@ -1,6 +1,6 @@
{
"name": "laravel/laravel",
"description": "The Laravel Framework.",
"name": "bytefury/crater",
"description": "Free & Open Source Invoice App for Freelancers & Small Businesses. https://craterapp.com",
"keywords": [
"framework",
"laravel"
@ -9,6 +9,7 @@
"type": "project",
"require": {
"php": "^7.2",
"aws/aws-sdk-php": "^3.137",
"barryvdh/laravel-dompdf": "^0.8.1",
"doctrine/dbal": "^2.10",
"fideloper/proxy": "^4.0",
@ -53,11 +54,20 @@
"minimum-stability": "dev",
"prefer-stable": true,
"scripts": {
"initial-setup": [
"test -f .env || (cp .env.example .env; php artisan key:generate 2>/dev/null; exit 0)"
],
"pre-install-cmd": [
"@initial-setup"
],
"pre-update-cmd": [
"@initial-setup"
],
"post-root-package-install": [
"php -r \"file_exists('.env') || copy('.env.example', '.env');\""
"@initial-setup"
],
"post-create-project-cmd": [
"php artisan key:generate --ansi"
"@initial-setup"
],
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",

1719
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,6 @@ return [
|
*/
'version' => '3.0.0',
'version' => '3.1.0',
];

View File

@ -13,6 +13,7 @@ class CreateUnitsTable extends Migration
*/
public function up()
{
if (!Schema::hasTable('units')) {
Schema::create('units', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
@ -21,6 +22,7 @@ class CreateUnitsTable extends Migration
$table->timestamps();
});
}
}
/**
* Reverse the migrations.

View File

@ -13,6 +13,7 @@ class CreatePaymentMethodsTable extends Migration
*/
public function up()
{
if (!Schema::hasTable('payment_methods')) {
Schema::create('payment_methods', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
@ -21,6 +22,7 @@ class CreatePaymentMethodsTable extends Migration
$table->timestamps();
});
}
}
/**
* Reverse the migrations.

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddUserIdToExpensesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('expenses', function (Blueprint $table) {
$table->integer('user_id')->unsigned()->nullable();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('expenses', function (Blueprint $table) {
$table->dropColumn('paid');
});
}
}

View File

@ -532,6 +532,14 @@ class CurrenciesTableSeeder extends Seeder
'thousand_separator' => '.',
'decimal_separator' => ','
],
[
'name' => 'Kyrgyzstani som',
'code' => 'KGS',
'symbol' => 'С̲ ',
'precision' => '2',
'thousand_separator' => '.',
'decimal_separator' => ','
],
];
foreach ($currencies as $currency) {

5019
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,19 +8,16 @@
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"babel-eslint": "^8.2.3",
"browser-sync": "^2.26.7",
"browser-sync-webpack-plugin": "^2.0.1",
"babel-eslint": "^8.2.6",
"cross-env": "^5.1",
"css-loader": "^0.28.8",
"eslint": "^4.14.0",
"eslint-config-standard": "^11.0.0-beta.0",
"eslint-plugin-import": "^2.11.0",
"eslint-plugin-node": "^5.2.1",
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-standard": "^3.0.1",
"eslint-plugin-vue": "^4.0.1",
"eslint": "^4.19.1",
"eslint-config-prettier": "^6.10.1",
"eslint-loader": "^3.0.3",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-vue": "^4.7.1",
"laravel-mix": "^5.0.0",
"prettier": "^2.0.2",
"resolve-url-loader": "3.1.0",
"sass": "^1.22.9",
"sass-loader": "7.*",
@ -35,18 +32,12 @@
"axios": "^0.19",
"bootstrap": "^4.1.0",
"chart.js": "^2.7.3",
"cross-env": "^5.1.4",
"easy-pie-chart": "^2.1.7",
"fs": "0.0.1-security",
"guid": "0.0.12",
"lodash": "^4.17.13",
"moment": "^2.18.1",
"npm": "^6.4.1",
"popper.js": "^1.12.9",
"sweet-modal-vue": "^2.0.0",
"sweetalert": "^2.1.2",
"toastr": "^2.1.4",
"upgrade": "^1.1.0",
"v-money": "^0.8.1",
"v-tooltip": "^2.0.2",
"vue": "^2.5.17",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
{
"/assets/js/app.js": "/assets/js/app.js?id=397e57d36ef22a2e14fc",
"/assets/css/crater.css": "/assets/css/crater.css?id=616996a79c1df69d18de"
"/assets/js/app.js": "/assets/js/app.js?id=2521d0dcc4cb4e4975a5",
"/assets/css/crater.css": "/assets/css/crater.css?id=84a4eeb53b0e6a937e44"
}

View File

@ -88,17 +88,27 @@ window.axios.interceptors.request.use(function (config) {
global.axios.interceptors.response.use(undefined, function (err) {
// Do something with request error
return new Promise((resolve, reject) => {
console.log(err.response)
if (err.response.data.error === 'invalid_credentials') {
window.toastr['error']('Invalid Credentials')
}
if (err.response.data && (err.response.statusText === 'Unauthorized' || err.response.data === ' Unauthorized.')) {
store.dispatch('auth/logout', true)
if (!err.response) {
window.toastr['error']('Network error: Please check your internet connection or wait until servers are back online')
console.log('Network error: Please check your internet connection.')
} else {
throw err
console.log(err.response)
if (err.response.data && (err.response.statusText === 'Unauthorized' || err.response.data === ' Unauthorized.')) {
// Unauthorized and log out
window.toastr['error']((err.response.data.message) ? err.response.data.message : 'Unauthorized')
store.dispatch('auth/logout', true)
} else if (err.response.data.errors) {
// Show a notification per error
const errors = JSON.parse(JSON.stringify(err.response.data.errors))
for (const i in errors) {
window.toastr['error'](errors[i])
}
})
} else {
// Unknown error
window.toastr['error']((err.response.data.message) ? err.response.data.message : 'Unknown error occurred')
}
}
return Promise.reject(err)
})
/**

View File

@ -1,69 +0,0 @@
<template>
<div class="graph-container">
<canvas
id="graph"
ref="graph"
/>
</div>
</template>
<script>
import Chart from 'chart.js'
export default {
props: {
labels: {
type: Array,
require: true,
default: Array
},
values: {
type: Array,
require: true,
default: Array
}
},
mounted () {
let context = this.$refs.graph.getContext('2d')
let options = {
responsive: true,
maintainAspectRatio: false,
legend: {
display: false
}
}
let data = {
labels: this.labels,
datasets: [
{
label: 'My First dataset',
backgroundColor: 'rgba(79, 196, 127,0.2)',
borderColor: 'rgba(79, 196, 127,1)',
borderWidth: 1,
hoverBackgroundColor: 'rgba(79, 196, 127,0.4)',
hoverBorderColor: 'rgba(79, 196, 127,1)',
data: this.values
}
]
}
this.myBarChart = new Chart(context, {
type: 'bar',
data: data,
options: options
})
},
beforeDestroy () {
this.myBarChart.destroy()
}
}
</script>
<style scoped>
.graph-container {
height: 300px;
}
</style>

View File

@ -1,71 +0,0 @@
<template>
<div class="graph-container">
<canvas
id="graph"
ref="graph"/>
</div>
</template>
<script>
import Chart from 'chart.js'
export default {
props: {
labels: {
type: Array,
require: true,
default: Array
},
values: {
type: Array,
require: true,
default: Array
},
bgColors: {
type: Array,
require: true,
default: Array
},
hoverBgColors: {
type: Array,
require: true,
default: Array
}
},
mounted () {
let context = this.$refs.graph.getContext('2d')
let options = {
responsive: true,
maintainAspectRatio: false
}
let data = {
labels: this.labels,
datasets: [
{
data: this.values,
backgroundColor: this.bgColors,
hoverBackgroundColor: this.hoverBgColors
}
]
}
this.myDoughnutChart = new Chart(context, {
type: 'doughnut',
data: data,
options: options
})
},
beforeDestroy () {
this.myDoughnutChart.destroy()
}
}
</script>
<style scoped>
.graph-container {
height: 300px;
}
</style>

View File

@ -1,8 +1,6 @@
<template>
<div class="graph-container">
<canvas
id="graph"
ref="graph" />
<canvas id="graph" ref="graph" />
</div>
</template>
@ -16,58 +14,56 @@ export default {
labels: {
type: Array,
require: true,
default: Array
default: Array,
},
values: {
type: Array,
require: true,
default: Array
default: Array,
},
invoices: {
type: Array,
require: true,
default: Array
default: Array,
},
expenses: {
type: Array,
require: true,
default: Array
default: Array,
},
receipts: {
type: Array,
require: true,
default: Array
default: Array,
},
income: {
type: Array,
require: true,
default: Array
default: Array,
},
formatMoney: {
type: Function,
require: false,
default: Function
default: Function,
},
FormatGraphMoney: {
type: Function,
require: false,
default: Function
}
default: Function,
},
},
computed: {
...mapGetters('currency', [
'defaultCurrency'
])
...mapGetters('currency', ['defaultCurrency']),
},
watch: {
labels (val) {
labels(val) {
this.update()
}
},
},
mounted () {
mounted() {
let self = this
let context = this.$refs.graph.getContext('2d')
let options = {
@ -77,13 +73,16 @@ export default {
enabled: true,
callbacks: {
label: function (tooltipItem, data) {
return self.FormatGraphMoney(tooltipItem.value, self.defaultCurrency)
}
}
return self.FormatGraphMoney(
tooltipItem.value * 100,
self.defaultCurrency
)
},
},
},
legend: {
display: false
}
display: false,
},
}
let data = {
labels: this.labels,
@ -107,7 +106,7 @@ export default {
pointHoverBorderWidth: 2,
pointRadius: 4,
pointHitRadius: 10,
data: this.invoices
data: this.invoices.map((invoice) => invoice / 100),
},
{
label: 'Receipts',
@ -128,7 +127,7 @@ export default {
pointHoverBorderWidth: 2,
pointRadius: 4,
pointHitRadius: 10,
data: this.receipts
data: this.receipts.map((receipt) => receipt / 100),
},
{
label: 'Expenses',
@ -149,7 +148,7 @@ export default {
pointHoverBorderWidth: 2,
pointRadius: 4,
pointHitRadius: 10,
data: this.expenses
data: this.expenses.map((expense) => expense / 100),
},
{
label: 'Net Income',
@ -170,34 +169,40 @@ export default {
pointHoverBorderWidth: 2,
pointRadius: 4,
pointHitRadius: 10,
data: this.income
}
]
data: this.income.map((_i) => _i / 100),
},
],
}
this.myLineChart = new Chart(context, {
type: 'line',
data: data,
options: options
options: options,
})
},
methods: {
update () {
update() {
this.myLineChart.data.labels = this.labels
this.myLineChart.data.datasets[0].data = this.invoices
this.myLineChart.data.datasets[1].data = this.receipts
this.myLineChart.data.datasets[2].data = this.expenses
this.myLineChart.data.datasets[3].data = this.income
this.myLineChart.data.datasets[0].data = this.invoices.map(
(invoice) => invoice / 100
)
this.myLineChart.data.datasets[1].data = this.receipts.map(
(receipt) => receipt / 100
)
this.myLineChart.data.datasets[2].data = this.expenses.map(
(expense) => expense / 100
)
this.myLineChart.data.datasets[3].data = this.income.map((_i) => _i / 100)
this.myLineChart.update({
lazy: true
lazy: true,
})
},
beforeDestroy () {
beforeDestroy() {
this.myLineChart.destroy()
}
}
},
},
}
</script>

View File

@ -1,72 +0,0 @@
<template>
<div class="graph-container">
<canvas
id="graph"
ref="graph" />
</div>
</template>
<script>
import Chart from 'chart.js'
export default {
props: {
labels: {
type: Array,
require: true,
default: Array
},
values: {
type: Array,
require: true,
default: Array
},
bgColors: {
type: Array,
require: true,
default: Array
},
hoverBgColors: {
type: Array,
require: true,
default: Array
}
},
mounted () {
let context = this.$refs.graph.getContext('2d')
let options = {
responsive: true,
maintainAspectRatio: false
}
let data = {
labels: this.labels,
datasets: [
{
data: this.values,
backgroundColor: this.bgColors,
hoverBackgroundColor: this.hoverBgColors
}
]
}
this.pieChart = new Chart(context, {
type: 'pie',
data: data,
options: options
})
},
beforeDestroy () {
this.pieChart.destroy()
}
}
</script>
<style scoped>
.graph-container {
height: 300px;
}
</style>

View File

@ -1,95 +0,0 @@
<template>
<div class="graph-container easy-pie-chart">
<svg width="100%" height="100%" viewBox="0 0 34 34" class="donut">
<circle :stroke-width="strokeWidth" class="donut-segment" cx="17" cy="17" r="15.91549430918954" fill="transparent" :stroke="strokeColor" stroke-dasharray="100 0" />
<circle :stroke-width="strokeWidth" :stroke="color" :stroke-dasharray="successProgress" class="donut-segment" cx="17" cy="17" r="15.91549430918954" fill="transparent" />
<!-- <g class="chart-text">
<text :style="'fill:' + color" x="48%" y="50%" class="chart-number" >
{{ progress }}
</text>
<text :style="'fill:' + color" x="73%" y="50%" class="chart-label" >
%
</text>
</g> -->
</svg>
</div>
</template>
<script>
export default {
props: {
values: {
type: Number,
require: true,
default: 100
},
strokeWidth: {
type: Number,
require: false,
default: 1.2
},
strokeColor: {
type: String,
require: true,
default: '#eeeeee'
},
color: {
type: String,
require: true,
default: '#007dcc'
}
},
data () {
return {
progress: 0
}
},
watch: {
values (newvalue, oldvalue) {
if (newvalue !== oldvalue) {
this.setProgress()
}
}
},
computed: {
successProgress () {
return this.progress + ' ' + (100 - this.progress)
},
remainProgress () {
return 100 - this.progress + ' ' + this.progress
},
},
mounted () {
this.setProgress()
},
methods: {
setProgress () {
let self = this
for (let i = 0; i < this.values; i++) {
setTimeout(function () {
++self.progress
}, 15 * i)
}
}
}
}
</script>
<style scoped>
.chart-text {
font: 6px "Montserrat", Arial, sans-serif;
fill: #000;
-moz-transform: translateY(0.25em);
-ms-transform: translateY(0.25em);
-webkit-transform: translateY(0.25em);
transform: translateY(0.5em);
}
.chart-number {
font-size: 8px;
line-height: 1;
text-anchor: middle;
}
.chart-label {
font-size: 5px;
text-transform: uppercase;
text-anchor: middle;
}
</style>

View File

@ -1,16 +1,16 @@
export default {
toggleSidebar () {
toggleSidebar() {
let icon = document.getElementsByClassName('hamburger')[0]
document.body.classList.toggle('sidebar-open')
icon.classList.toggle('is-active')
},
addClass (el, className) {
addClass(el, className) {
if (el.classList) el.classList.add(className)
else el.className += ' ' + className
},
hasClass (el, className) {
hasClass(el, className) {
const hasClass = el.classList
? el.classList.contains(className)
: new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className)
@ -18,33 +18,38 @@ export default {
return hasClass
},
reset (prefix) {
reset(prefix) {
let regx = new RegExp('\\b' + prefix + '(.*)?\\b', 'g')
document.body.className = document.body.className.replace(regx, '')
},
setLayout (layoutName) {
setLayout(layoutName) {
this.reset('layout-')
document.body.classList.add('layout-' + layoutName)
},
setSkin (skinName) {
setSkin(skinName) {
this.reset('skin-')
document.body.classList.add('skin-' + skinName)
},
setLogo (logoSrc) {
setLogo(logoSrc) {
document.getElementById('logo-desk').src = logoSrc
},
formatMoney (amount, currency = 0) {
formatMoney(amount, currency = 0) {
if (!currency) {
currency = {precision: 2, thousand_separator: ',', decimal_separator: '.', symbol: '$'}
currency = {
precision: 2,
thousand_separator: ',',
decimal_separator: '.',
symbol: '$',
}
}
amount = amount / 100
let {precision, decimal_separator, thousand_separator, symbol} = currency
let { precision, decimal_separator, thousand_separator, symbol } = currency
try {
precision = Math.abs(precision)
@ -52,25 +57,44 @@ export default {
const negativeSign = amount < 0 ? '-' : ''
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(precision)).toString()
let j = (i.length > 3) ? i.length % 3 : 0
let i = parseInt(
(amount = Math.abs(Number(amount) || 0).toFixed(precision))
).toString()
let j = i.length > 3 ? i.length % 3 : 0
let moneySymbol = `<span style="font-family: sans-serif">${symbol}</span>`
return moneySymbol + ' ' + negativeSign + (j ? i.substr(0, j) + thousand_separator : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand_separator) + (precision ? decimal_separator + Math.abs(amount - i).toFixed(precision).slice(2) : '')
return (
moneySymbol +
' ' +
negativeSign +
(j ? i.substr(0, j) + thousand_separator : '') +
i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand_separator) +
(precision
? decimal_separator +
Math.abs(amount - i)
.toFixed(precision)
.slice(2)
: '')
)
} catch (e) {
console.log(e)
}
},
formatGraphMoney (amount, currency = 0) {
formatGraphMoney(amount, currency = 0) {
if (!currency) {
currency = {precision: 2, thousand_separator: ',', decimal_separator: '.', symbol: '$'}
currency = {
precision: 2,
thousand_separator: ',',
decimal_separator: '.',
symbol: '$',
}
}
amount = amount / 100
let {precision, decimal_separator, thousand_separator, symbol} = currency
let { precision, decimal_separator, thousand_separator, symbol } = currency
try {
precision = Math.abs(precision)
@ -78,25 +102,76 @@ export default {
const negativeSign = amount < 0 ? '-' : ''
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(precision)).toString()
let j = (i.length > 3) ? i.length % 3 : 0
let i = parseInt(
(amount = Math.abs(Number(amount) || 0).toFixed(precision))
).toString()
let j = i.length > 3 ? i.length % 3 : 0
let moneySymbol = `${symbol}`
return moneySymbol + ' ' + negativeSign + (j ? i.substr(0, j) + thousand_separator : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand_separator) + (precision ? decimal_separator + Math.abs(amount - i).toFixed(precision).slice(2) : '')
return (
moneySymbol +
' ' +
negativeSign +
(j ? i.substr(0, j) + thousand_separator : '') +
i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand_separator) +
(precision
? decimal_separator +
Math.abs(amount - i)
.toFixed(precision)
.slice(2)
: '')
)
} catch (e) {
console.log(e)
}
},
checkValidUrl (url) {
let pattern = new RegExp('^(https?:\\/\\/)?' + // protocol
checkValidUrl(url) {
let pattern = new RegExp(
'^(https?:\\/\\/)?' + // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
'(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
'(\\#[-a-z\\d_]*)?$', 'i') // fragment locator
'(\\#[-a-z\\d_]*)?$',
'i'
) // fragment locator
return !!pattern.test(url)
},
fallbackCopyTextToClipboard(text) {
var textArea = document.createElement('textarea')
textArea.value = text
// Avoid scrolling to bottom
textArea.style.top = '0'
textArea.style.left = '0'
textArea.style.position = 'fixed'
document.body.appendChild(textArea)
textArea.focus()
textArea.select()
try {
var successful = document.execCommand('copy')
var msg = successful ? 'successful' : 'unsuccessful'
console.log('Fallback: Copying text command was ' + msg)
} catch (err) {
console.error('Fallback: Oops, unable to copy', err)
}
document.body.removeChild(textArea)
},
copyTextToClipboard(text) {
if (!navigator.clipboard) {
this.fallbackCopyTextToClipboard(text)
return
}
navigator.clipboard.writeText(text).then(
function () {
return true
},
function (err) {
return false
}
)
},
}

View File

@ -62,14 +62,14 @@
"four_zero_four": "404",
"you_got_lost": "عفواً! يبدو أنك قد تهت!",
"go_home": "عودة إلى الرئيسية",
"setting_updated": "تم تحديث الإعدادات بنجاح",
"select_state": "اختر الولاية/المنطقة",
"select_country": "اختر الدولة",
"select_city": "اختر المدينة",
"street_1": "عنوان الشارع 1",
"street_2": "عنوان الشارع 2",
"action_failed": "فشلت العملية"
"action_failed": "فشلت العملية",
"retry": "أعد المحاولة"
},
"dashboard": {
"select_year": "اختر السنة",
@ -155,7 +155,7 @@
"select_a_customer": "اختر العميل",
"type_or_click": "اكتب أو اضغط للاختيار",
"confirm_delete": "لن تكون قادراً على استرجاع هذا العميل | لن تكون قادراً على استرجاع هؤلاء العملاء",
"confirm_delete": "لن تتمكن من استرداد هذا العميل وجميع الفواتير والتقديرات والمدفوعات ذات الصلة. | لن تتمكن من استرداد هؤلاء العملاء وجميع الفواتير والتقديرات والمدفوعات ذات الصلة.",
"created_message": "تم إنشاء العملاء بنجاح",
"updated_message": "تم تحديث العملاء بنجاح",
"deleted_message": "تم حذف العملاء بنجاح | تم حذف العميل بنجاح"
@ -412,6 +412,8 @@
"title": "النفقات",
"expenses_list": "قائمة النفقات",
"expense_title": "Title",
"select_a_customer": "حدد عميلاً",
"customer": "العميل",
"contact": "تواصل",
"category": "الفئة",
"from_date": "من تاريخ",
@ -750,7 +752,14 @@
"progress_text": "سوف يستغرق التحديث بضع دقائق. يرجى عدم تحديث الشاشة أو إغلاق النافذة قبل انتهاء التحديث",
"update_success": "تم تحديث النظام! يرجى الانتظار حتى يتم إعادة تحميل نافذة المتصفح تلقائيًا.",
"latest_message": "لا يوجد تحديثات متوفرة! لديك حالياً أحدث نسخة.",
"current_version": "النسخة الحالية"
"current_version": "النسخة الحالية",
"download_zip_file": "تنزيل ملف ZIP",
"unzipping_package": "حزمة فك الضغط",
"copying_files": "نسخ الملفات",
"running_migrations": "إدارة عمليات الترحيل",
"finishing_update": "تحديث التشطيب",
"update_failed": "فشل التحديث",
"update_failed_text": "آسف! فشل التحديث الخاص بك في: {step} خطوة"
}
},
"wizard": {

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,7 @@
},
"general": {
"view_pdf": "View PDF",
"copy_pdf_url": "Copy PDF Url",
"download_pdf": "Download PDF",
"save": "Save",
"cancel": "Cancel",
@ -70,14 +71,14 @@
"go_home": "Go Home",
"test_mail_conf": "Test Mail Configuration",
"send_mail_successfully": "Mail sent successfully",
"setting_updated": "Setting updated successfully",
"select_state": "Select state",
"select_country": "Select Country",
"select_city": "Select City",
"street_1": "Street 1",
"street_2": "Street 2",
"action_failed": "Action Failed"
"action_failed": "Action Failed",
"retry": "Retry"
},
"dashboard": {
"select_year": "Select year",
@ -163,7 +164,7 @@
"select_a_customer": "Select a customer",
"type_or_click": "Type or click to select",
"confirm_delete": "You will not be able to recover this Customer | You will not be able to recover these Customers",
"confirm_delete": "You will not be able to recover this customer and all the related Invoices, Estimates and Payments. | You will not be able to recover these customers and all the related Invoices, Estimates and Payments.",
"created_message": "Customer created successfully",
"updated_message": "Customer updated successfully",
"deleted_message": "Customer deleted successfully | Customers deleted successfully"
@ -230,6 +231,7 @@
"convert_to_invoice": "Convert to Invoice",
"mark_as_sent": "Mark as Sent",
"send_estimate": "Send Estimate",
"resend_estimate": "Resend Estimate",
"record_payment": "Record Payment",
"add_estimate": "Add Estimate",
"save_estimate": "Save Estimate",
@ -316,6 +318,7 @@
"notes": "Notes",
"view": "View",
"send_invoice": "Send Invoice",
"resend_invoice": "Resend Invoice",
"invoice_template": "Invoice Template",
"template": "Template",
"mark_as_sent": "Mark as sent",
@ -426,7 +429,9 @@
"expenses": {
"title": "Expenses",
"expenses_list": "Expenses List",
"select_a_customer": "Select a customer",
"expense_title": "Title",
"customer": "Customer",
"contact": "Contact",
"category": "Category",
"from_date": "From Date",
@ -679,7 +684,7 @@
"mode_name": "Mode Name",
"payment_mode_added": "Payment Mode Added",
"payment_mode_updated": "Payment Mode Updated",
"payment_mode_confirm_delete":"You will not be able to recover this Payment Mode",
"payment_mode_confirm_delete": "You will not be able to recover this Payment Mode",
"already_in_use": "Payment Mode is already in use",
"deleted_message": "Payment Mode deleted successfully"
},
@ -691,7 +696,7 @@
"unit_name": "Unit Name",
"item_unit_added": "Item Unit Added",
"item_unit_updated": "Item Unit Updated",
"item_unit_confirm_delete":"You will not be able to recover this Item unit",
"item_unit_confirm_delete": "You will not be able to recover this Item unit",
"already_in_use": "Item Unit is already in use",
"deleted_message": "Item Unit deleted successfully"
}
@ -785,7 +790,14 @@
"progress_text": "It will just take a few minutes. Please do not refresh the screen or close the window before the update finishes",
"update_success": "App has been updated! Please wait while your browser window gets reloaded automatically.",
"latest_message": "No update available! You are on the latest version.",
"current_version": "Current Version"
"current_version": "Current Version",
"download_zip_file": "Download ZIP file",
"unzipping_package": "Unzipping Package",
"copying_files": "Copying Files",
"running_migrations": "Running Migrations",
"finishing_update": "Finishing Update",
"update_failed": "Update Failed",
"update_failed_text": "Sorry! Your update failed on : {step} step"
}
},
"wizard": {

View File

@ -62,14 +62,14 @@
"four_zero_four": "404",
"you_got_lost": "Whoops! ¡Te perdiste!",
"go_home": "Volver al Inicio",
"setting_updated": "Configuración actualizada con éxito",
"select_state": "Seleccionar estado",
"select_country": "Seleccionar país",
"select_city": "Seleccionar ciudad",
"street_1": "Calle 1",
"street_2": "Calle 2",
"action_failed": "Accion Fallida"
"action_failed": "Accion Fallida",
"retry": "Procesar de nuevo"
},
"dashboard": {
"select_year": "Seleccionar año",
@ -155,7 +155,7 @@
"select_a_customer": "Selecciona un cliente",
"type_or_click": "Escriba o haga clic para seleccionar",
"confirm_delete": "No podrá recuperar este cliente | No podrá recuperar estos clientes",
"confirm_delete": "No podrá recuperar este cliente y todas las facturas, estimaciones y pagos relacionados. | No podrá recuperar estos clientes y todas las facturas, estimaciones y pagos relacionados.",
"created_message": "Cliente creado con éxito",
"updated_message": "Cliente actualizado con éxito",
"deleted_message": "Cliente eliminado correctamente | Clientes eliminados exitosamente"
@ -412,6 +412,8 @@
"expenses_list": "Lista de gastos",
"expense_title": "Título",
"contact": "Contacto",
"customer": "Cliente",
"select_a_customer": "Selecciona un cliente",
"category": "Categoría",
"from_date": "Desde la fecha",
"to_date": "Hasta la fecha",
@ -749,7 +751,14 @@
"progress_text": "Solo tomará unos minutos. No actualice la pantalla ni cierre la ventana antes de que finalice la actualización.",
"update_success": "¡La aplicación ha sido actualizada! Espere mientras la ventana de su navegador se vuelve a cargar automáticamente.",
"latest_message": "¡Actualización no disponible! Estás en la última versión.",
"current_version": "Versión actual"
"current_version": "Versión actual",
"download_zip_file": "Descargar archivo ZIP",
"unzipping_package": "Descomprimir paquete",
"copying_files": "Copiando documentos",
"running_migrations": "Ejecutar migraciones",
"finishing_update": "Actualización final",
"update_failed": "Actualización fallida",
"update_failed_text": "¡Lo siento! Su actualización falló el: {step} paso"
}
},
"wizard": {

View File

@ -17,6 +17,7 @@
"save": "Sauvegarder",
"cancel": "Annuler",
"update": "Mise à jour",
"deselect": "Retirer",
"download": "Télécharger",
"from_date": "A partir de la date",
"to_date": "À ce jour",
@ -28,7 +29,7 @@
"filter": "Filtre",
"delete": "Effacer",
"edit": "Modifier",
"view": "Vue",
"view": "Voir",
"add_new_item": "Ajoute un nouvel objet",
"clear_all": "Tout effacer",
"showing": "Montrant",
@ -62,14 +63,21 @@
"four_zero_four": "404",
"you_got_lost": "Oups! Vous vous êtes perdus!",
"go_home": "Rentrer chez soi",
"test_mail_conf": "Tester la configuration",
"send_mail_successfully": "Mail envoyé avec succès",
"setting_updated": "Réglage mis à jour avec succès",
"select_state": "Sélectionnez l'état",
"select_country": "Choisissez le pays",
"select_city": "Sélectionnez une ville",
"street_1": "Rue 1",
"street_2": "Rue # 2",
"action_failed": "Action : échoué"
"action_failed": "Action : échoué",
"sort_by": "Trier par",
"ascending": "Ascendant",
"descending": "Descendant",
"subject": "matière",
"message": "Message",
"retry": "Réessayez"
},
"dashboard": {
"select_year": "Sélectionnez l'année",
@ -160,7 +168,7 @@
"select_a_customer": "Sélectionnez un client",
"type_or_click": "Tapez ou cliquez pour sélectionner",
"confirm_delete": "Vous ne pourrez pas récupérer ce client | Vous ne pourrez pas récupérer ces clients",
"confirm_delete": "Vous ne pourrez pas récupérer ce client et toutes les factures, devis et paiements associés. | Vous ne serez pas en mesure de récupérer ces clients et toutes les factures, devis et paiements associés.",
"created_message": "Client créé avec succès",
"updated_message": "Client mis à jour avec succès",
"deleted_message": "Client supprimé avec succès | Les clients supprimés avec succès"
@ -202,24 +210,24 @@
"all": "Tout",
"paid": "Payé",
"unpaid": "Non payé",
"customer": "CLIENT CLIENT",
"ref_no": "REF NO.",
"number": "NOMBRE",
"customer": "Client",
"ref_no": "Réf.",
"number": "N°",
"amount_due": "MONTANT DÛ",
"partially_paid": "Partiellement payé",
"total": "Totale",
"total": "Total",
"discount": "Remise",
"sub_total": "Total partiel",
"estimate_number": "Numéro destimation",
"estimate_number": "N°",
"ref_number": "Numéro de ref",
"contact": "Contact",
"add_item": "Ajouter un article",
"date": "Date",
"due_date": "Date déchéance",
"due_date": "Date d'échéance",
"expiry_date": "Date dexpiration",
"status": "Statut",
"add_tax": "Ajouter une taxe",
"amount": "Montante",
"amount": "Montant",
"action": "action",
"notes": "Remarques",
"tax": "Impôt",
@ -227,7 +235,7 @@
"convert_to_invoice": "Convertir en facture",
"mark_as_sent": "Marquer comme envoyé",
"send_estimate": "Envoyer un devis",
"record_payment": "Record de paiement",
"record_payment": "Enregistrer un paiement",
"add_estimate": "Ajouter un devis",
"save_estimate": "Sauvegarder le devis",
"confirm_conversion": "Vous souhaitez convertir ce devis en facture?",
@ -269,14 +277,17 @@
"quantity": "Quantité",
"price": "Prix",
"discount": "Remise",
"total": "Totale",
"total": "Total",
"total_discount": "Remise totale",
"sub_total": "Total partiel",
"tax": "Impôt",
"amount": "Montante",
"amount": "Montant",
"select_an_item": "Tapez ou cliquez pour sélectionner un élément",
"type_item_description": "Type Item Description (optionnel)"
}
},
"no_matching_estimates": "Aucune estimation correspondante!",
"user_email_does_not_exist": "L'e-mail de l'utilisateur n'existe pas",
"something_went_wrong": "quelque chose a mal tourné"
},
"invoices": {
"title": "Factures",
@ -287,13 +298,13 @@
"all": "Toute",
"paid": "Payé",
"unpaid": "Non payé",
"customer": "CLIENTE CLIENT",
"paid_status": "Statut payé",
"customer": "CLIENT",
"paid_status": "Paiement",
"ref_no": "REF NO.",
"number": "NOMBRE",
"number": "N°",
"amount_due": "MONTANT DÛ",
"partially_paid": "Partiellement payé",
"total": "Totale Total",
"total": "Total",
"discount": "Remise",
"sub_total": "Total partiel",
"invoice": "Facture | Factures",
@ -302,21 +313,23 @@
"contact": "Contact",
"add_item": "Ajouter un article",
"date": "Date",
"due_date": "Date déchéance",
"due_date": "Date d'échéance",
"status": "Statut",
"add_tax": "Ajouter une taxe",
"amount": "Montante Montant",
"amount": "Montant",
"action": "action",
"notes": "Remarques",
"view": "Vue",
"view": "Voir",
"send_invoice": "Envoyer une facture",
"cloned_successfully": "Facture clonée avec succès",
"clone_invoice": "Cloner",
"invoice_template": "Modèle de facture",
"template": "Modèle",
"mark_as_sent": "Marquer comme envoyé",
"invoice_mark_as_sent": "Cette facture sera marquée comme envoyé",
"confirm_send": "Cette facture sera envoyée par courrier électronique au client.",
"invoice_date": "Date de facturation",
"record_payment": "Record de paiement",
"record_payment": "Enregister un paiement",
"add_new_invoice": "Ajouter une nouvelle facture",
"update_expense": "Frais de mise à jour",
"edit_invoice": "Modifier la facture",
@ -335,11 +348,11 @@
"quantity": "Quantité",
"price": "Prix",
"discount": "Remise",
"total": "Totale Total",
"total": "Total",
"total_discount": "Remise totale",
"sub_total": "Total partiel",
"tax": "Impôt",
"amount": "Montante Montant",
"amount": "Montant",
"select_an_item": "Tapez ou cliquez pour sélectionner un élément",
"type_item_description": "Type Item Description (optionnel)"
},
@ -349,7 +362,12 @@
"updated_message": "Facture mise à jour avec succès",
"deleted_message": "La Facture a été supprimée ! | Les Factures ont été supprimées !",
"marked_as_sent_message": "Facture supprimée avec succès | Factures supprimées avec succès",
"invalid_due_amount_message": "Le paiement entré est supérieur au montant total dû pour cette facture. Veuillez vérifier et réessayer"
"invalid_due_amount_message": "Le paiement entré est supérieur au montant total dû pour cette facture. Veuillez vérifier et réessayer",
"confirm_send_invoice": "Cette facture sera envoyée par email au client",
"no_matching_invoices": "Aucune facture correspondante!",
"confirm_clone": "Cette facture sera clonée dans une nouvelle facture",
"user_email_does_not_exist": "L'e-mail de l'utilisateur n'existe pas",
"something_went_wrong": "quelque chose a mal tourné"
},
"credit_notes": {
"title": "Notes de crédit",
@ -357,7 +375,7 @@
"credit_notes": "Notes de crédit",
"contact": "Contact",
"date": "Date",
"amount": "Montante Montant",
"amount": "Montant Montant",
"action": "action",
"credit_number": "Numéro de crédit",
"notes": "Remarques",
@ -368,7 +386,7 @@
"quantity": "Quantité",
"price": "Prix",
"discount": "Remise",
"total": "Totale Total",
"total": "Total",
"total_discount": "Remise totale",
"sub_total": "Total partiel",
"tax": "Impôt"
@ -377,12 +395,12 @@
"payments": {
"title": "Paiements",
"payments_list": "Liste de paiements",
"record_payment": "Record de paiement",
"customer": "Client Client",
"record_payment": "Enregistrer un paiement",
"customer": "Client",
"date": "Date",
"amount": "Montant Montant",
"amount": "Montant",
"action": "action",
"payment_number": "Numéro de paiement",
"payment_number": "N°",
"payment_mode": "Mode de paiement",
"invoice": "Facture dachat",
"note": "Remarque",
@ -391,6 +409,7 @@
"edit_payment": "Modifier le paiement",
"view_payment": "Voir le paiement",
"add_new_payment": "Ajouter un nouveau paiement",
"send_payment_receipt": "Envoyer le reçu",
"save_payment": "Enregistrer le paiement",
"update_payment": "Mettre à jour le paiement",
"payment": "Paiement | Paiements",
@ -403,13 +422,19 @@
"created_message": "Paiement créé avec succès",
"updated_message": "Paiement mis à jour avec succès",
"deleted_message": "Paiement supprimé avec succès | Paiements supprimés avec succès",
"invalid_amount_message": "Le montant du paiement est invalide"
"invalid_amount_message": "Le montant du paiement est invalide",
"confirm_send_payment": "Ce paiement sera envoyé par e-mail au client",
"send_payment_successfully": "Paiement envoyé avec succès",
"user_email_does_not_exist": "L'e-mail de l'utilisateur n'existe pas",
"something_went_wrong": "quelque chose a mal tourné"
},
"expenses": {
"title": "Dépenses",
"expenses_list": "Liste des dépenses",
"expense_title": "Titre",
"contact": "Contact",
"customer": "Client Client",
"select_a_customer": "Sélectionnez un client",
"category": "Catégorie",
"from_date": "A partir de la date",
"to_date": "À ce jour",
@ -423,7 +448,7 @@
"date": "Date de dépense",
"add_expense": "Ajouter une dépense",
"add_new_expense": "Ajouter une nouvelle dépense",
"save_expense": "Économiser des dépenses",
"save_expense": "Enregistrer la dépense",
"update_expense": "Frais de mise à jour",
"download_receipt": "Télécharger le reçu",
"edit_expense": "Modifier les dépenses",
@ -447,7 +472,8 @@
"new_category": "Nouvelle catégorie",
"category": "Catégorie | Les catégories",
"select_a_category": "choisissez une catégorie"
}
},
"customer": "Client"
},
"login": {
"email": "Email",
@ -460,7 +486,8 @@
"enter_email": "Entrer email",
"enter_password": "Entrer le mot de passe",
"retype_password": "Retaper le mot de passe",
"login_placeholder": "mail@example.com"
"login_placeholder": "mail@example.com",
"password_reset_successfully": "Réinitialisation du mot de passe réussie"
},
"reports": {
"title": "rapport",
@ -499,7 +526,7 @@
"invoice": "Facture d'achat",
"invoice_date": "Date de facturation",
"due_date": "Date déchéance",
"amount": "Montante ",
"amount": "Montant ",
"contact_name": "Nom du contact",
"status": "Statut"
},
@ -507,7 +534,7 @@
"estimate": "Devis",
"estimate_date": "Date du devis",
"due_date": "Date d'échéance",
"estimate_number": "Numéro d'estimation",
"estimate_number": "N°",
"ref_number": "Numéro de ref",
"amount": "Montant",
"contact_name": "Nom du contact",
@ -527,6 +554,7 @@
"menu_title": {
"account_settings": "Paramètres du compte",
"company_information": "Informations sur la société",
"customization": "Personnalisation",
"preferences": "Préférences",
"notifications": "Les notifications",
"tax_types": "Types de taxe",
@ -591,10 +619,90 @@
"state": "Etat",
"city": "Ville",
"address": "Adresse",
"zip": "Zip",
"save": "sauver",
"zip": "Code postal",
"save": "Sauvegarder",
"updated_message": "Informations sur la société mises à jour avec succès"
},
"customization": {
"customization": "Personnalisation",
"save": "Sauvegarder",
"addresses": {
"title": "Adresses",
"section_description": "You can set Customer Billing Address and Customer Shipping Address Format (Displayed in PDF only). ",
"customer_billing_address": "Adresse de paiement",
"customer_shipping_address": "Adresse de livraison",
"company_address": "Adresse de l'entreprise",
"insert_fields": "Ajouter des champs",
"contact": "Contact",
"address": "Addresse",
"display_name": "Nom",
"primary_contact_name": "Nom du contact principal",
"email": "Email",
"website": "Website",
"name": "Nom",
"country": "Pays",
"state": "State",
"city": "Ville",
"company_name": "Nom de l'entreprise",
"address_street_1": "Rue",
"address_street_2": "Complément",
"phone": "Téléphone",
"zip_code": "Code postal",
"address_setting_updated": "Adresse mise à jour avec succès"
},
"updated_message": "Informations de l'entreprise mises à jour",
"invoices": {
"title": "Factures",
"notes": "Notes",
"invoice_prefix": "Préfixe",
"invoice_settings": "Paramètre",
"autogenerate_invoice_number": "Générer automatiquement le numéro de facture",
"invoice_setting_description": "Désactivez cette option si vous ne souhaitez pas générer automatiquement les numéros de facture à chaque fois que vous en créez une nouvelle.",
"enter_invoice_prefix": "Ajouter le préfixe de facture",
"terms_and_conditions": "Termes et conditions",
"invoice_setting_updated": "Paramètres de facturation mis à jour"
},
"estimates": {
"title": "Devis",
"estimate_prefix": "Préfixe",
"estimate_settings": "Paramètre",
"autogenerate_estimate_number": "Générer automatiquement le numéro de devis",
"estimate_setting_description": "Désactivez cette option si vous ne souhaitez pas générer automatiquement les numéros de devis à chaque fois que vous en créez un nouveau.",
"estimate_setting_updated": "Paramètres de devis mis à jour"
},
"payments": {
"title": "Paiements",
"payment_prefix": "Préfixe",
"payment_settings": "Paramètre",
"autogenerate_payment_number": "Générer automatiquement le numéro de paiement",
"payment_setting_description": "Désactivez cette option si vous ne souhaitez pas générer automatiquement les numéros de paiement à chaque fois que vous en créez un nouveau.",
"payment_setting_updated": "Les paramètres de paiement ont bien été mis à jour",
"payment_mode": "Mode de paiement",
"add_payment_mode": "Ajouter un mode de paiement",
"mode_name": "Nom",
"payment_mode_added": "Mode de paiement ajouté",
"payment_mode_updated": "Mode de paiement mis à jour",
"payment_mode_confirm_delete": "Êtes-vous sur de supprimer ce mode de paiement ?",
"already_in_use": "Ce mode de paiement existe déjà.",
"deleted_message": "Mode de paiement supprimé avec succès"
},
"items": {
"title": "Articles",
"units": "Unités",
"add_item_unit": "Ajouter une unité",
"unit_name": "Nom",
"item_unit_added": "Unité ajouté",
"item_unit_updated": "Unité mis à jour",
"item_unit_confirm_delete": "Êtes-vous sur de supprimer cette unité ?",
"already_in_use": "Cette unité existe déjà",
"deleted_message": "Unité supprimé avec succès"
}
},
"account_settings": {
"profile_picture": "Image de profil",
"name": "Nom",
@ -602,7 +710,7 @@
"password": "Mot de passe",
"confirm_password": "Confirmez le mot de passe",
"account_settings": "Paramètres du compte",
"save": "sauver",
"save": "Sauvegarder",
"section_description": "Vous pouvez mettre à jour votre nom, votre email et votre mot de passe en utilisant le formulaire ci-dessous.",
"updated_message": "Paramètres du compte mis à jour avec succès"
},
@ -617,10 +725,10 @@
"email": "Envoyer des notifications à",
"description": "Quelles notifications par courrier électronique souhaitez-vous recevoir lorsque quelque chose change?",
"invoice_viewed": "Facture consultée",
"invoice_viewed_desc": "Lorsque votre client visualise la facture envoyée via le tableau de bord du cratère.",
"estimate_viewed": "Estimation vue",
"estimate_viewed_desc": "Lorsque votre client visualise le devis envoyé via le tableau de bord du cratère.",
"save": "sauver",
"invoice_viewed_desc": "Lorsque le client visualise la facture envoyée via le tableau de bord de Neptune.",
"estimate_viewed": "Devis consulté",
"estimate_viewed_desc": "Lorsque le client visualise le devis envoyé via le tableau de bord de Neptune.",
"save": "Sauvegarder",
"email_save_message": "Email enregistré avec succès",
"invoice_viewed_message": "Facture consultée",
"estimate_viewed_message": "Estimation vue",
@ -650,7 +758,7 @@
"description": "Des catégories sont requises pour ajouter des entrées de dépenses. Vous pouvez ajouter ou supprimer ces catégories selon vos préférences.",
"add_new_category": "Ajouter une nouvelle catégorie",
"category_name": "Nom de catégorie",
"category_description": "La description",
"category_description": "Description",
"created_message": "Catégorie de dépenses créée avec succès",
"deleted_message": "La catégorie de dépenses a été supprimée avec succès",
"updated_message": "Catégorie de dépenses mise à jour avec succès",
@ -666,7 +774,7 @@
"discount_setting": "Réglage de remise",
"discount_per_item": "Remise par article",
"discount_setting_description": "Activez cette option si vous souhaitez ajouter une remise à des postes de facture individuels. Par défaut, les remises sont ajoutées directement à la facture.",
"save": "sauver",
"save": "Sauvegarder",
"preference": "Préférence | Préférences",
"general_settings": "Préférences par défaut pour le système.",
"updated_message": "Préférences mises à jour avec succès",
@ -687,7 +795,14 @@
"progress_text": "Cela ne prendra que quelques minutes. S'il vous plaît ne pas actualiser l'écran ou fermer la fenêtre avant la fin de la mise à jour",
"update_success": "App a été mis à jour! Veuillez patienter pendant le rechargement automatique de la fenêtre de votre navigateur.",
"latest_message": "Pas de mise a jour disponible! Vous êtes sur la dernière version.",
"current_version": "Version actuelle"
"current_version": "Version actuelle",
"download_zip_file": "Télécharger le fichier ZIP",
"unzipping_package": "Dézipper le package",
"copying_files": "Copie de fichiers",
"running_migrations": "Exécution de migrations",
"finishing_update": "Mise à jour de finition",
"update_failed": "Mise à jour a échoué",
"update_failed_text": "Désolé! Votre mise à jour a échoué à: {step} étape"
}
},
"wizard": {
@ -772,7 +887,8 @@
"success": {
"mail_variables_save_successfully": "Email configuré avec succès",
"database_variables_save_successfully": "Base de données configurée avec succès."
}
},
"skip": "sauter"
},
"layout_login": {
"copyright_crater": "Copyright @ Crater - 2020",
@ -781,7 +897,6 @@
"small_businesses": "Petites entreprises ",
"crater_help": "Crater vous aide à suivre vos dépenses, à enregistrer vos paiements et à générer de belles",
"invoices_and_estimates": "factures et devis avec possibilité de choisir plusieurs modèles."
},
"validation": {
"invalid_url": "URL invalide (ex: http://www.crater.com)",
@ -812,6 +927,7 @@
"maximum_options_error": "Maximum de {max} options sélectionnées. Commencez par supprimer une option sélectionnée pour en sélectionner une autre.",
"notes_maxlength": "Les notes ne doivent pas dépasser 255 caractères.",
"address_maxlength": "L'adresse ne doit pas dépasser 255 caractères.",
"ref_number_maxlength": "Le numéro de référence ne doit pas dépasser 255 caractères."
"ref_number_maxlength": "Le numéro de référence ne doit pas dépasser 255 caractères.",
"email_already_taken": "Un compte est déjà associé à cette adresse e-mail."
}
}

View File

@ -6,6 +6,7 @@ import es from './es.json'
import ar from './ar.json'
import de from './de.json'
import pt_BR from './pt-br.json'
import it from './it.json'
Vue.use(VueI18n)
@ -17,8 +18,9 @@ const i18n = new VueI18n({
es,
ar,
de,
pt_BR
}
pt_BR,
it,
},
})
export default i18n

View File

@ -0,0 +1,929 @@
{
"_comment": "Italian - IT translation - by Alessandro Fuda - Milan, Italy - 20/03/2020 - Coronavirus's times But towards spring :-) ",
"navigation": {
"dashboard": "Dashboard",
"customers": "Clienti",
"items": "Commesse",
"invoices": "Fatture",
"expenses": "Spese",
"estimates": "Preventivi",
"payments": "Pagamenti",
"reports": "Reports",
"settings": "Configurazione",
"logout": "Logout"
},
"general": {
"view_pdf": "Vedi PDF",
"download_pdf": "Download PDF",
"save": "Salva",
"cancel": "Elimina",
"update": "Aggiorna",
"deselect": "Deseleziona",
"download": "Download",
"from_date": "Dalla Data",
"to_date": "Alla Data",
"from": "Da",
"to": "A",
"sort_by": "Ordina per",
"ascending": "Crescente",
"descending": "Decrescente",
"subject": "Oggetto",
"message": "Messaggio",
"go_back": "Torna indietro",
"back_to_login": "Torna al Login?",
"home": "Home",
"filter": "Filtro",
"delete": "Elimina",
"edit": "Modifica",
"view": "Visualizza",
"add_new_item": "Aggiungi nuova Commessa",
"clear_all": "Pulisci tutto",
"showing": "Showing",
"of": "di",
"actions": "Azioni",
"subtotal": "SUBTOTALE",
"discount": "SCONTO",
"fixed": "Fissato",
"percentage": "Percentuale",
"tax": "TASSA",
"total_amount": "AMMONTARE TOTALE",
"bill_to": "Fattura a",
"ship_to": "Invia a",
"due": "Dovuto",
"draft": "Bozza",
"sent": "Inviata",
"all": "Tutte",
"select_all": "Seleziona tutto",
"choose_file": "Clicca per selezionare un file",
"choose_template": "Scegli un modello",
"choose": "Scegli",
"remove": "Rimuovi",
"powered_by": "Prodotto da",
"bytefury": "Bytefury",
"select_a_status": "Seleziona uno Stato",
"select_a_tax": "Seleziona una Tassa",
"search": "Cerca",
"are_you_sure": "Sei sicuro/a?",
"list_is_empty": "La lista è vuota.",
"no_tax_found": "Nessuna Tassa trovata!",
"four_zero_four": "404",
"you_got_lost": "Hoops! Ti sei perso",
"go_home": "Vai alla Home",
"test_mail_conf": "Configurazione della mail di test",
"send_mail_successfully": "Mail inviata con successo",
"setting_updated": "Configurazioni aggiornate con successo",
"select_state": "Seleziona lo Stato",
"select_country": "Seleziona Paese",
"select_city": "Seleziona Città",
"street_1": "Indirizzo 1",
"street_2": "Indirizzo 2",
"action_failed": "Errore",
"retry": "Retry"
},
"dashboard": {
"select_year": "Seleziona anno",
"cards": {
"due_amount": "Somma dovuta",
"customers": "Clienti",
"invoices": "Fatture",
"estimates": "Preventivi"
},
"chart_info": {
"total_sales": "Vendite",
"total_receipts": "Ricevute",
"total_expense": "Uscite",
"net_income": "Guadagno netto",
"year": "Seleziona anno"
},
"weekly_invoices": {
"title": "Fatture a settimana"
},
"monthly_chart": {
"title": "Entrate & Uscite"
},
"recent_invoices_card": {
"title": "Fatture insolute",
"due_on": "Data di scadenza",
"customer": "Cliente",
"amount_due": "Ammontare dovuto",
"actions": "Azioni",
"view_all": "Vedi tutto"
},
"recent_estimate_card": {
"title": "Preventivi recenti",
"date": "Data",
"customer": "Cliente",
"amount_due": "Ammontare dovuto",
"actions": "Azioni",
"view_all": "Vedi tutto"
}
},
"tax_types": {
"name": "Nome",
"description": "Descrizione",
"percent": "Percento",
"compound_tax": "Tassa composta"
},
"customers": {
"title": "Clienti",
"add_customer": "Aggiungi cliente",
"contacts_list": "Lista clienti",
"name": "Nome",
"display_name": "Mostra nome",
"primary_contact_name": "Riferimento",
"contact_name": "Nome Contatto",
"amount_due": "Ammontare dovuto",
"email": "Email",
"address": "Indirizzo",
"phone": "Telefono",
"website": "Sito web",
"country": "Paese",
"state": "Stato",
"city": "Città",
"zip_code": "Codice Postale",
"added_on": "Aggiunto il",
"action": "Azione",
"password": "Password",
"street_number": "Numero Civico",
"primary_currency": "Valùta Principale",
"add_new_customer": "Aggiungi nuovo Cliente",
"save_customer": "Salva Cliente",
"update_customer": "Aggiorna Cliente",
"customer": "Cliente | Clienti",
"new_customer": "Nuovo cliente",
"edit_customer": "Modifica Cliente",
"basic_info": "Informazioni",
"billing_address": "Indirizzo di Fatturazione",
"shipping_address": "Indirizzo di Spedizione",
"copy_billing_address": "Copia da Fatturazione",
"no_customers": "Ancora nessun Cliente!",
"no_customers_found": "Nessun cliente trovato!",
"list_of_customers": "Qui ci sarà la lista dei tuoi clienti",
"primary_display_name": "Mostra il Nome Principale",
"select_currency": "Selezione Valùta",
"select_a_customer": "Seleziona Cliente",
"type_or_click": "Scrivi o clicca per selezionare",
"confirm_delete": "Non sarai in grado di recuperare questo cliente e tutte le relative fatture, stime e pagamenti. | Non sarai in grado di recuperare questi clienti e tutte le relative fatture, stime e pagamenti.",
"created_message": "Cliente creato con successo",
"updated_message": "Cliente aggiornato con successo",
"deleted_message": "Cliente cancellato con successo | Clienti cancellati con successo"
},
"items": {
"title": "Commesse",
"items_list": "Lista Commesse",
"name": "Nome",
"unit": "Unità/Tipo",
"description": "Descrizione",
"added_on": "Aggiunto il",
"price": "Prezzo",
"date_of_creation": "Data di creazione",
"action": "Azione",
"add_item": "Aggiungi Commessa",
"save_item": "Salva",
"update_item": "Aggiorna",
"item": "Commessa | Commesse",
"add_new_item": "Aggiungi nuova Commessa",
"new_item": "Nuova Commessa",
"edit_item": "Modifica Commessa",
"no_items": "Ancora nessuna commessa!",
"list_of_items": "Qui ci sarà la lista delle commesse.",
"select_a_unit": "Seleziona",
"taxes": "Imposte",
"item_attached_message": "Non puoi eliminare una Commessa che è già attiva",
"confirm_delete": "Non potrai ripristinare la Commessa | Non potrai ripristinare le Commesse",
"created_message": "Commessa creata con successo",
"updated_message": "Commessa aggiornata con successo",
"deleted_message": "Commessa eliminata con successo | Commesse eliminate con successo"
},
"estimates": {
"title": "Preventivi",
"estimate": "Preventivo | Preventivi",
"estimates_list": "Lista Preventivi",
"days": "{days} Giorni",
"months": "{months} Mese",
"years": "{years} Anno",
"all": "Tutti",
"paid": "Pagato",
"unpaid": "Non pagato",
"customer": "CLIENTE",
"ref_no": "RIF N.",
"number": "NUMERO",
"amount_due": "AMMONTARE DOVUTO",
"partially_paid": "Pagamento Parziale",
"total": "Totale",
"discount": "Sconto",
"sub_total": "Sub Totale",
"estimate_number": "Preventivo Numero",
"ref_number": "Numero di Rif.",
"contact": "Contatto",
"add_item": "Aggiungi un item",
"date": "Data",
"due_date": "Data di pagamento",
"expiry_date": "Data di scadenza",
"status": "Status",
"add_tax": "Aggiungi Imposta",
"amount": "Ammontare",
"action": "Azione",
"notes": "Note",
"tax": "Imposta",
"estimate_template": "Modello",
"convert_to_invoice": "Converti in Fattura",
"mark_as_sent": "Segna come Inviata",
"send_estimate": "Invia preventivo",
"record_payment": "Registra Pagamento",
"add_estimate": "Aggiungi Preventivo",
"save_estimate": "Salva Preventivo",
"confirm_conversion": "Questo preventivo verrà usato per generare una nuova fattura.",
"conversion_message": "Fattura creata",
"confirm_send_estimate": "Questo preventivo verrà inviato al cliente via mail",
"confirm_mark_as_sent": "Questo preventivo verrà contrassegnato come inviato",
"confirm_mark_as_accepted": "Questo preventivo verrà contrassegnato come Accettato",
"confirm_mark_as_rejected": "Questo preventivo verrà contrassegnato come Rifiutato",
"no_matching_estimates": "Nessun preventivo trovato!",
"mark_as_sent_successfully": "Preventivo contrassegnato come inviato con successo",
"send_estimate_successfully": "Preventivo inviato con successo",
"errors": {
"required": "Campo obbligatorio"
},
"accepted": "Accettato",
"sent": "Inviato",
"draft": "Bozza",
"declined": "Rifiutato",
"new_estimate": "Nuovo Preventivo",
"add_new_estimate": "Crea Nuovo Preventivo",
"update_Estimate": "Aggiorna preventivo",
"edit_estimate": "Modifica Preventivo",
"items": "Commesse",
"Estimate": "Preventivo | Preventivi",
"add_new_tax": "Aggiungi una nuova tassa/imposta",
"no_estimates": "Ancora nessun preventivo!",
"list_of_estimates": "Questa sezione conterrà la lista dei preventivi.",
"mark_as_rejected": "Segna come Rifiutato",
"mark_as_accepted": "Segna come Accettato",
"marked_as_accepted_message": "Preventivo contrassegnato come accettato",
"marked_as_rejected_message": "Preventivo contrassegnato come rifiutato",
"confirm_delete": "Non potrai più recuperare questo preventivo | Non potrai più recuperare questi preventivi",
"created_message": "Preventivo creato con successo",
"updated_message": "Preventivo modificato con successo",
"deleted_message": "Preventivo eliminato con successo | Preventivi eliminati con successo",
"user_email_does_not_exist": "La Email utente non esiste",
"something_went_wrong": "Si è verificato un errore",
"item": {
"title": "Titolo Commessa",
"description": "Descrizione",
"quantity": "Quantità",
"price": "Prezzo",
"discount": "Sconto",
"total": "Totale",
"total_discount": "Sconto Totale",
"sub_total": "Sub Totale",
"tax": "Tasse",
"amount": "Ammontare",
"select_an_item": "Scrivi o clicca per selezionare un item",
"type_item_description": "Scrivi una Descrizione (opzionale)"
}
},
"invoices": {
"title": "Fatture",
"invoices_list": "Lista Fatture",
"days": "{days} Giorni",
"months": "{months} Mese",
"years": "{years} Anno",
"all": "Tutti",
"paid": "Pagato",
"unpaid": "Insoluto",
"customer": "CLIENTE",
"paid_status": "STATO DI PAGAMENTO",
"ref_no": "RIF N.",
"number": "NUMERO",
"amount_due": "AMMONTARE DOVUTO",
"partially_paid": "Parzialmente Pagata",
"total": "Totale",
"discount": "Sconto",
"sub_total": "Sub Totale",
"invoice": "Fattura | Fatture",
"invoice_number": "Numero Fattura",
"ref_number": "Rif Numero",
"contact": "Contatto",
"add_item": "Aggiungi Commessa/Item",
"date": "Data",
"due_date": "Data di pagamento",
"status": "Stato",
"add_tax": "Aggiungi Imposta",
"amount": "Ammontare",
"action": "Azione",
"notes": "Note",
"view": "Vedi",
"send_invoice": "Invia Fattura",
"invoice_template": "Modello Fattura",
"template": "Modello",
"mark_as_sent": "Segna come inviata",
"confirm_send_invoice": "Questa fattura sarà inviata via Mail al Cliente",
"invoice_mark_as_sent": "Questa fattura sarà contrassegnata come inviata",
"confirm_send": "Questa fattura sarà inviata via Mail al Cliente",
"invoice_date": "Data fattura",
"record_payment": "Registra Pagamento",
"add_new_invoice": "Aggiungi nuova Fattura",
"update_expense": "Aggiorna Costo",
"edit_invoice": "Modifica Fattura",
"new_invoice": "Nuova Fattura",
"save_invoice": "Salva fattura",
"update_invoice": "Aggiorna Fattura",
"add_new_tax": "Aggiungi tassa/imposta",
"no_invoices": "Ancora nessuna fattura!",
"list_of_invoices": "Questa sezione conterrà la lista delle Fatture.",
"select_invoice": "Seleziona Fattura",
"no_matching_invoices": "Nessuna fattura trovata!",
"mark_as_sent_successfully": "Fattura contassegnata come inviata con successo",
"send_invoice_successfully": "Fattura inviata con successo",
"cloned_successfully": "Fattura copiata con successo",
"clone_invoice": "Clona Fattura",
"confirm_clone": "Questa fattura verrà clonata in una nuova fattura",
"item": {
"title": "Titolo Commessa",
"description": "Descrizione",
"quantity": "Quantità",
"price": "Prezzo",
"discount": "Sconto",
"total": "Totale",
"total_discount": "Sconto Totale",
"sub_total": "Sub Totale",
"tax": "Tassa",
"amount": "Ammontare",
"select_an_item": "Scrivi o clicca per selezionare un item",
"type_item_description": "Scrivi una descrizione (opzionale)"
},
"payment_attached_message": "Una delle fatture selezionate ha già associato un pagamento. Assicurati di eliminare il pagamento associato prima di procedere con la rimozione",
"confirm_delete": "Non potrai recuperare la Fattura cancellata | Non potrai recuperare le Fatture cancellate",
"created_message": "Fattura creata con successo",
"updated_message": "Fattura aggiornata con successo",
"deleted_message": "Fattura cancellata con successo | Fatture cancellate con successo",
"marked_as_sent_message": "Fattura contrassegnata come inviata con successo",
"user_email_does_not_exist": "La Email utente non esiste",
"something_went_wrong": "Si è verificato un errore",
"invalid_due_amount_message": "L'ammontare totale della fattura non può essere inferiore all'ammontare totale pagato per questa fattura. Modifica la fattura o cancella i pagamenti associati per continuare."
},
"credit_notes": {
"title": "Note di Credito",
"credit_notes_list": "Lista Note di Credito",
"credit_notes": "Note di Credito",
"contact": "Contatta",
"date": "Data",
"amount": "Ammontare",
"action": "Azione",
"credit_number": "Numero Credito",
"notes": "Note",
"confirm_delete": "Vuoi cancellare questa nota di credito?",
"item": {
"title": "Titolo",
"description": "Descrizione",
"quantity": "Quantità",
"price": "Prezzo",
"discount": "Sconto",
"total": "Totale",
"total_discount": "Sconto Totale",
"sub_total": "Sub Totale",
"tax": "Tassa"
}
},
"payments": {
"title": "Pagamenti",
"payments_list": "Lista Pagamenti",
"record_payment": "Registra Pagamento",
"customer": "Cliente",
"date": "Data",
"amount": "Ammontare",
"action": "Azione",
"payment_number": "Numero di pagamento",
"payment_mode": "Modalità di Pagamento",
"invoice": "Fattura",
"note": "Note",
"add_payment": "Aggiungi Pagamento",
"new_payment": "Nuovo Pagamento",
"edit_payment": "Modifica Pagamento",
"view_payment": "Vedi Pagamento",
"add_new_payment": "Aggiungi nuovo pagamento",
"send_payment_receipt": "Invia ricevuta di pagamento",
"save_payment": "Salva pagamento",
"update_payment": "Aggiorna pagamento",
"payment": "Pagamento | Pagamenti",
"no_payments": "Ancora nessun pagamento!",
"no_matching_payments": "Non ci sono pagamenti!",
"list_of_payments": "Questa sezione conterrà la lista dei pagamenti.",
"select_payment_mode": "Seleziona modalità di pagamento",
"confirm_send_payment": "Questo pagamento verrà inviato via email al cliente",
"send_payment_successfully": "Pagamento inviato con successo",
"user_email_does_not_exist": "Email utente non esiste",
"something_went_wrong": "si è verificato un errore",
"confirm_delete": "Non potrai recuperare questo pagamento | Non potrai recuperare questi pagamenti",
"created_message": "Pagamento creato con successo",
"updated_message": "Pagamento aggiornato con successo",
"deleted_message": "Pagamento cancellato con successo | Pagamenti cancellati con successo",
"invalid_amount_message": "L'ammontare del pagamento non è valido"
},
"expenses": {
"title": "Spese",
"expenses_list": "Lista Costi",
"expense_title": "Titolo",
"contact": "Contatto",
"category": "Categoria",
"from_date": "Dalla Data",
"to_date": "Alla Data",
"expense_date": "Data",
"description": "Descrizione",
"receipt": "Ricevuta",
"amount": "Ammontare",
"action": "Azione",
"note": "Nota",
"category_id": "Id categoria",
"date": "Data Spesa",
"add_expense": "Aggiungi Spesa",
"add_new_expense": "Aggiungi nuova Spesa",
"save_expense": "Salva la Spesa",
"update_expense": "Aggiorna Spesa",
"download_receipt": "Scarica la Ricevuta",
"edit_expense": "Modifica Spesa",
"new_expense": "Nuova Spesa",
"expense": "Spesa | Spese",
"no_expenses": "Ancora nessuna spesa!",
"list_of_expenses": "Questa sezione conterrà la lista delle Spese.",
"confirm_delete": "Non potrai recuperare questa spesa | Non potrai recuperare queste spese",
"created_message": "Spesa creata con successo",
"updated_message": "Spesa modificata con successo",
"deleted_message": "Spesa cancellata con successo | Spese cancellate con successo",
"categories": {
"categories_list": "Lista categorie",
"title": "Titolo",
"name": "Nome",
"description": "Descrizione",
"amount": "Ammontare",
"actions": "Azioni",
"add_category": "Aggiungi Categoria",
"new_category": "Nuova Categoria",
"category": "Categoria | Categorie",
"select_a_category": "Seleziona Categoria"
}
},
"login": {
"email": "Email",
"password": "Password",
"forgot_password": "Password dimenticata?",
"or_signIn_with": "o fai login con",
"login": "Login",
"register": "Registrati",
"reset_password": "Resetta Password",
"password_reset_successfully": "Password Resettata con successo",
"enter_email": "Inserisci email",
"enter_password": "Inserisci Password",
"retype_password": "Ridigita Password",
"login_placeholder": "mail@example.com"
},
"reports": {
"title": "Report",
"from_date": "Da",
"to_date": "A",
"status": "Status",
"paid": "Pagato",
"unpaid": "Non pagato",
"download_pdf": "Scarica PDF",
"view_pdf": "Vedi PDF",
"update_report": "Aggiorna Report",
"report": "Report | Reports",
"profit_loss": {
"profit_loss": "Guadagni & Perdite",
"to_date": "A",
"from_date": "Da",
"date_range": "Seleziona intervallo date"
},
"sales": {
"sales": "Vendite",
"date_range": "Seleziona intervallo date",
"to_date": "A",
"from_date": "Da",
"report_type": "Tipo di report"
},
"taxes": {
"taxes": "Tasse",
"to_date": "Alla data",
"from_date": "Dalla data",
"date_range": "Seleziona intervallo date"
},
"errors": {
"required": "Campo obbligatorio"
},
"invoices": {
"invoice": "Fattura",
"invoice_date": "Data fattura",
"due_date": "Data di pagamento",
"amount": "Ammontare",
"contact_name": "Nome contatto",
"status": "Status"
},
"estimates": {
"estimate": "Preventivo",
"estimate_date": "Data preventivo",
"due_date": "Data di pagamento",
"estimate_number": "Numero di preventivo",
"ref_number": "Numero di Rif.",
"amount": "Ammontare",
"contact_name": "Nome contatto",
"status": "Status"
},
"expenses": {
"expenses": "Spese",
"category": "Categoria",
"date": "Data",
"amount": "Ammontare",
"to_date": "Alla data",
"from_date": "Dalla data",
"date_range": "Seleziona intervallo date"
}
},
"settings": {
"menu_title": {
"account_settings": "Impostazioni Account",
"company_information": "Informazioni Azienda",
"customization": "Personalizzazione",
"preferences": "Opzioni",
"notifications": "Notifiche",
"tax_types": "Tupi di Tasse",
"expense_category": "Categorie di spesa",
"update_app": "Aggiorna App"
},
"title": "Impostazioni",
"setting": "Opzione | Impostazioni",
"general": "Generale",
"language": "Lingua",
"primary_currency": "Valuta Principale",
"timezone": "Time Zone",
"date_format": "Formato data",
"currencies": {
"title": "Valute",
"currency": "Valùta | Valute",
"currencies_list": "Lista valute",
"select_currency": "Seleziona Valùta",
"name": "Nome",
"code": "Codice",
"symbol": "Simbolo",
"precision": "Precisione",
"thousand_separator": "Separatore migliaia",
"decimal_separator": "Separatore decimali",
"position": "Posizione",
"position_of_symbol": "Posizione del Simbolo",
"right": "Destra",
"left": "Sinistra",
"action": "Azione",
"add_currency": "Aggiungi Valùta"
},
"mail": {
"host": "Mail Host",
"port": "Mail Port",
"driver": "Mail Driver",
"secret": "Secret",
"mailgun_secret": "Mailgun Secret",
"mailgun_domain": "Domain",
"mailgun_endpoint": "Mailgun Endpoint",
"ses_secret": "SES Secret",
"ses_key": "SES Key",
"password": "Mail Password",
"username": "Mail Username",
"mail_config": "Configurazione Mail",
"from_name": "Nome Mittente Mail",
"from_mail": "Indirizzo Mittente Mail",
"encryption": "Mail Encryption",
"mail_config_desc": "Form per Configurazione Driver Mail per invio mail dall'App. Puoi anche configurare providers di terze parti come Sendgrid, SES, etc.."
},
"pdf": {
"title": "Configurazione PDF",
"footer_text": "Testo Footer",
"pdf_layout": "Layout PDF"
},
"company_info": {
"company_info": "Info azienda",
"company_name": "Nome azienda",
"company_logo": "Logo azienda",
"section_description": "Informazioni sulla tua azienda che saranno mostrate in fattura, preventivi ed altri documenti creati dell'applicazione.",
"phone": "Telefono",
"country": "Paese",
"state": "Stato",
"city": "Città",
"address": "Indirizzo",
"zip": "CAP",
"save": "Salva",
"updated_message": "Informazioni Azienda aggiornate con successo."
},
"customization": {
"customization": "personalizzazione",
"save": "Salva",
"addresses": {
"title": "Indirizzi",
"section_description": "Puoi settare l'indirizzo di fatturazione del Cliente e/o il formato dell'indirizzo di spedizione (Mostrato solo sul PDF). ",
"customer_billing_address": "Indirizzo Fatturazione Cliente",
"customer_shipping_address": "Indirizzo spedizione Cliente",
"company_address": "Indirizzo Azienda",
"insert_fields": "Inserisci Campi",
"contact": "Contatto",
"address": "Indirizzo",
"display_name": "Mostra nome",
"primary_contact_name": "Nome contatto primario",
"email": "Email",
"website": "Sito web",
"name": "Nome",
"country": "Paese",
"state": "Stato",
"city": "Città",
"company_name": "Nome Azienda",
"address_street_1": "Indirizzo 1",
"address_street_2": "Indirizzo 2",
"phone": "Telefono",
"zip_code": "CAP/ZIP Code",
"address_setting_updated": "Indirizzo aggiornato con Successo"
},
"updated_message": "Info azienda aggiornate con successo",
"invoices": {
"title": "Fatture",
"notes": "Note",
"invoice_prefix": "Prefisso Fattura",
"invoice_settings": "Impostazioni fattura",
"autogenerate_invoice_number": "Auto genera numero di fattura",
"invoice_setting_description": "Disabilita, se non vuoi auto-generare i numeri delle fatture ogni volta che crei una nuova fattura.",
"enter_invoice_prefix": "Inserisci prefisso fattura",
"terms_and_conditions": "Termini e Condizioni",
"invoice_setting_updated": "Impostazioni fatture aggiornate con successo"
},
"estimates": {
"title": "Preventivi",
"estimate_prefix": "Prefisso Preventivi",
"estimate_settings": "Impostazioni Preventivi",
"autogenerate_estimate_number": "Auto-genera Numero di preventivo",
"estimate_setting_description": "Disabilita, se non vuoi autogenerare il numero di preventivo ogni volta che ne viene creato uno nuovo.",
"enter_estimate_prefix": "Inserisci prefisso preventivo",
"estimate_setting_updated": "Impostazioni preventivi aggiornate con successo"
},
"payments": {
"title": "Pagamenti",
"payment_prefix": "Prefisso Pagamento",
"payment_settings": "Impostazioni Pagamento",
"autogenerate_payment_number": "Auto genera il numero di Pagamento",
"payment_setting_description": "Disabilita, se non vuoi autogenerare il numero di pagamento ogni volta che ne viene creato uno nuovo.",
"enter_payment_prefix": "Inserisci prefisso di pagamento",
"payment_setting_updated": "Impostazioni di pagamento aggiornate con successo",
"payment_mode": "Modalità di pagamento",
"add_payment_mode": "Aggiungi modalità di pagamento",
"mode_name": "Nome modalità",
"payment_mode_added": "Modalità di pagamento aggiunta",
"payment_mode_updated": "Modalità di pagamento aggiornata",
"payment_mode_confirm_delete": "Non potrai ripristinare la modalità di pagamento",
"already_in_use": "Modalità di pagamento già in uso",
"deleted_message": "Payment Mode deleted successfully"
},
"items": {
"title": "Items",
"units": "unità",
"add_item_unit": "Aggiungi Unità Item",
"unit_name": "Nome",
"item_unit_added": "Unità aggiunta",
"item_unit_updated": "Unità aggiornata",
"item_unit_confirm_delete": "Non potrai ripristinare questa unità Item",
"already_in_use": "Unità Item già in uso",
"deleted_message": "Unità item eliminata con successo"
}
},
"account_settings": {
"profile_picture": "Immagine profilo",
"name": "Nome",
"email": "Email",
"password": "Password",
"confirm_password": "Conferma Password",
"account_settings": "Impostazioni Account",
"save": "Salva",
"section_description": "Puoi aggiornare nome email e password utilizzando il form qui sotto.",
"updated_message": "Impostazioni account aggiornate con successo"
},
"user_profile": {
"name": "Nome",
"email": "Email",
"password": "Password",
"confirm_password": "Conferma Password"
},
"notification": {
"title": "Notifica",
"email": "Invia notifiche a",
"description": "Quali notifiche email vorresti ricevere quando qualcosa cambia?",
"invoice_viewed": "Fattura visualizzata",
"invoice_viewed_desc": "Quando il cliente visualizza la fattura inviata via dashboard applicazione.",
"estimate_viewed": "Preventivo visualizzato",
"estimate_viewed_desc": "Quando il cliente visualizza il preventivo inviato dall'applicazione.",
"save": "Salva",
"email_save_message": "Email salvata con successo",
"please_enter_email": "Inserisci Email"
},
"tax_types": {
"title": "Tipi di Imposta",
"add_tax": "Aggiungi Imposta",
"description": "Puoi aggiongere e rimuovere imposte a piacimento. Vengono supportate Tasse differenti per prodotti/servizi specifici esattamento come per le fatture.",
"add_new_tax": "Aggiungi nuova imposta",
"tax_settings": "Impostazioni Imposte",
"tax_per_item": "Tassa per prodotto/servizio",
"tax_name": "Nome imposta",
"compound_tax": "Imposta composta",
"percent": "Percento",
"action": "Azione",
"tax_setting_description": "Abilita se vuoi aggiungere imposte specifiche per prodotti o servizi. Di default le imposte sono aggiunte direttamente alla fattura.",
"created_message": "Tipo di imposta creato con successo",
"updated_message": "Tipo di imposta aggiornato con successo",
"deleted_message": "Tipo di imposta eliminato con successo",
"confirm_delete": "Non potrai ripristinare questo tipo di imposta",
"already_in_use": "Imposta già in uso"
},
"expense_category": {
"title": "Categorie di spesa",
"action": "Azione",
"description": "Le categorie sono necessarie per aggiungere delle voci di spesa. Puoi aggiungere o eliminare queste categorie in base alle tue preferenze.",
"add_new_category": "Aggiungi nuova categoria",
"category_name": "Nome Categoria",
"category_description": "Descrizione",
"created_message": "Categoria di spesa creata con successo",
"deleted_message": "Categoria di spesa eliminata con successo",
"updated_message": "Categoria di spesa aggiornata con successo",
"confirm_delete": "Non potrai ripristinare questa categoria di spesa",
"already_in_use": "Categoria già in uso"
},
"preferences": {
"currency": "Valùta",
"language": "Lingua",
"time_zone": "Time Zone",
"fiscal_year": "Anno finanziario",
"date_format": "Formato Data",
"discount_setting": "Impostazione Sconto",
"discount_per_item": "Sconto Per Item ",
"discount_setting_description": "Abilita se vuoi aggiungere uno sconto ad uno specifica fattura. Di default, lo sconto è aggiunto direttamente in fattura.",
"save": "Salva",
"preference": "Preferenza | Preferenze",
"general_settings": "Impostazioni di default del sistema.",
"updated_message": "Preferenze aggiornate con successo",
"select_language": "seleziona lingua",
"select_time_zone": "Seleziona Time Zone",
"select_date_formate": "Seleziona Formato Data",
"select_financial_year": "Seleziona anno finanziario"
},
"update_app": {
"title": "Aggiorna App",
"description": "Puoi facilmente aggiornare l'app. Aggiorna cliccando sul bottone qui sotto",
"check_update": "Controllo aggiornamenti",
"avail_update": "Aggiornamento disponibile",
"next_version": "Versione successiva",
"update": "Aggiorna ora",
"update_progress": "Aggiornamento in corso...",
"progress_text": "Sarà necessario qualche minuto. Per favore non aggiornare la pagina e non chiudere la finestra prima che l'aggiornamento sia completato",
"update_success": "L'App è aggiornata! Attendi che la pagina venga ricaricata automaticamente.",
"latest_message": "Nessun aggiornamneto disponibile! Sei già alla versione più recente.",
"current_version": "Versione corrente",
"download_zip_file": "Scarica il file ZIP",
"unzipping_package": "Pacchetto di decompressione",
"copying_files": "Copia dei file",
"running_migrations": "Esecuzione delle migrazioni",
"finishing_update": "Aggiornamento di finitura",
"update_failed": "Aggiornamento non riuscito",
"update_failed_text": "Scusate! L'aggiornamento non è riuscito il: passaggio {step}"
}
},
"wizard": {
"account_info": "Informazioni Account",
"account_info_desc": "I dettagli qui sotto verranno usati per creare l'account principale dell'Amministratore. Puoi modificarli in qualsiasi momento dopo esserti loggato come Amministratore.",
"name": "Nome",
"email": "Email",
"password": "Password",
"confirm_password": "Conferma Password",
"save_cont": "Salva & Continua",
"company_info": "Informazioni Azienda",
"company_info_desc": "Questa informazione verrà mostrata nelle fatture. Puoi modificare queste informazione in un momento successivo dalla pagina delle impostazioni.",
"company_name": "Nome Azienda",
"company_logo": "Logo Azienda",
"logo_preview": "Anteprima Logo",
"preferences": "Impostazioni",
"preferences_desc": "Impostazioni di default del sistema.",
"country": "Paese",
"state": "Stato",
"city": "Città",
"address": "Indirizzo",
"street": "Indirizzo1 | Indirizzo2",
"phone": "Telefono",
"zip_code": "CAP/Zip Code",
"go_back": "Torna indietro",
"currency": "Valùta",
"language": "Lingua",
"time_zone": "Time Zone",
"fiscal_year": "Anno Finanziario",
"date_format": "Formato Date",
"from_address": "Indirizzo - Da",
"username": "Username",
"next": "Successivo",
"continue": "Continua",
"skip": "Salta",
"database": {
"database": "URL del sito & database",
"connection": "Connessione Database",
"host": "Database Host",
"port": "Database - Porta",
"password": "Database Password",
"app_url": "App URL",
"username": "Database Username",
"db_name": "Database Nome",
"desc": "Crea un database sul tuo server e setta le credenziali usando il form qui sotto."
},
"permissions": {
"permissions": "Permessi",
"permission_confirm_title": "Sei sicuro di voler continuare?",
"permission_confirm_desc": "Controllo sui permessi Cartelle, fallito",
"permission_desc": "Qui sotto la lista dei permessi richiesti per far funzionare correttamente l'App. Se il controllo dei permessi fallisce, assicurati di aggiornare/modificare i permessi sulle cartelle."
},
"mail": {
"host": "Mail Host",
"port": "Mail - Porta",
"driver": "Mail Driver",
"secret": "Secret",
"mailgun_secret": "Mailgun Secret",
"mailgun_domain": "Domain",
"mailgun_endpoint": "Mailgun Endpoint",
"ses_secret": "SES Secret",
"ses_key": "SES Key",
"password": "Mail Password",
"username": "Mail Username",
"mail_config": "Configurazione Mail",
"from_name": "Nome mittente mail",
"from_mail": "Indirizzo mittente mail",
"encryption": "Tipo di cifratura Mail",
"mail_config_desc": "Form per configurazione del 'driver mail' per inviare emails dall'App. Puoi anche configurare servizi di terze parti come Sendgrid, SES, ecc.."
},
"req": {
"system_req": "Requisiti di Sistema",
"php_req_version": "Php (versione {version} richiesta)",
"check_req": "Controllo Requisiti",
"system_req_desc": "Crater ha alcuni requisiti di sistema. Assicurati che il server ha la versione di php richiesta e tutte le estensioni necessarie."
},
"errors": {
"migrate_failed": "Migrate Failed",
"database_variables_save_error": "Cannot write configuration to .env file. Please check its file permissions",
"mail_variables_save_error": "Email configuration failed.",
"connection_failed": "Database connection failed",
"database_should_be_empty": "Database should be empty"
},
"success": {
"mail_variables_save_successfully": "Email configurata con successo",
"database_variables_save_successfully": "Database configurato con successo."
}
},
"layout_login": {
"copyright_crater": "Copyright @ Crater - 2020",
"super_simple_invoicing": "Fatturazione super semplice",
"for_freelancer": "per Freelancers &",
"small_businesses": "Medio Piccoli Business ",
"crater_help": "Crater ti aiuta a tracciare le spese, registrare pagamenti e generare graziose",
"invoices_and_estimates": "fatture & preventivi con possibilità di scegliere tra diversi modelli."
},
"validation": {
"invalid_url": "URL non valido (es: http://www.crater.com)",
"required": "Campo obbligatorio",
"email_incorrect": "Email non corretta.",
"email_already_taken": "Email già in uso.",
"email_does_not_exist": "L'utente con questa email non esiste",
"item_unit_already_taken": "Questo nome item è già utilizzato",
"payment_mode_already_taken": "Questa modalità di pagamento è già stata inserita.",
"send_reset_link": "Invia Link di Reset",
"not_yet": "Non ancora? Invia di nuovo",
"password_min_length": "La password deve contenere {count} caratteri",
"name_min_length": "Il nome deve avere almeno {count} lettere.",
"enter_valid_tax_rate": "Inserisci un tasso di imposta valido",
"numbers_only": "Solo numeri.",
"characters_only": "Solo caratteri.",
"password_incorrect": "La Password deve essere identica",
"password_length": "La password deve essere lunga {count} caratteri.",
"qty_must_greater_than_zero": "La quantità deve essere maggiore di zero.",
"price_greater_than_zero": "Il prezzo deve essere maggiore di zero.",
"payment_greater_than_zero": "Il pagamento deve essere maggiore di zero.",
"payment_greater_than_due_amount": "Il pagamento inserito è maggiore di quello indicato in fattura.",
"quantity_maxlength": "La Quantità non può essere maggiore di 20 cifre.",
"price_maxlength": "Il prezzo non può contenere più di 20 cifre.",
"price_minvalue": "Il prezzo deve essere maggiore di 0.",
"amount_maxlength": "La somma non deve contenere più di 20 cifre.",
"amount_minvalue": "La somma deve essere maggiore di 0.",
"description_maxlength": "La Descrizione non deve superare i 255 caratteri.",
"subject_maxlength": "L'Oggetto non deve superare i 100 caratter.",
"message_maxlength": "Il messaggio non può superare i 255 caratteri.",
"maximum_options_error": "Massimo di {max} opzioni selezionate. Per selezionare un'altra opzione deseleziona prima una opzione.",
"notes_maxlength": "Le note non possono superare i 255 caratteri.",
"address_maxlength": "L'Indirizzo non può eccedere i 255 caratteri.",
"ref_number_maxlength": "Il Numero di Riferimento non può superare i 255 caratteri.",
"prefix_maxlength": "Il Prefisso non può superare i 5 caratteri.",
"something_went_wrong": "Si è verificato un errore"
}
}

View File

@ -62,14 +62,14 @@
"four_zero_four": "404",
"you_got_lost": "Ops! Se perdeu!",
"go_home": "Ir para Home",
"setting_updated": "Configuração atualizada com sucesso",
"select_state": "Selecione Estado",
"select_country": "Selecionar pais",
"select_city": "Selecionar cidade",
"street_1": "Rua 1",
"street_2": "Rua # 2",
"action_failed": "Ação: Falhou"
"action_failed": "Ação: Falhou",
"retry": "Atualização falhou"
},
"dashboard": {
"select_year": "Selecione Ano",
@ -155,7 +155,7 @@
"select_a_customer": "Selecione um cliente",
"type_or_click": "Digite ou clique para selecionar",
"confirm_delete": "Você não poderá recuperar este cliente | Você não poderá recuperar esses clientes",
"confirm_delete": "Você não poderá recuperar este cliente e todas as faturas, estimativas e pagamentos relacionados. | Você não poderá recuperar esses clientes e todas as faturas, estimativas e pagamentos relacionados.",
"created_message": "Cliente criado com sucesso",
"updated_message": "Cliente atualizado com sucesso",
"deleted_message": "Cliente excluído com sucesso | Clientes excluídos com sucesso"
@ -414,6 +414,7 @@
"expense_title": "Título",
"contact": "Contato",
"category": "Categoria",
"customer": "Cliente",
"from_date": "A partir da Data",
"to_date": "Até a Data",
"expense_date": "Data",
@ -527,7 +528,7 @@
"date_range": "Selecionar período"
}
},
"settings": {
"settings": {
"menu_title": {
"account_settings": "Configurações da conta",
"company_information": "Informações da Empresa",
@ -750,7 +751,14 @@
"progress_text": "Levará apenas alguns minutos. Não atualize a tela ou feche a janela antes que a atualização seja concluída",
"update_success": "O aplicativo foi atualizado! Aguarde enquanto a janela do navegador é recarregada automaticamente.",
"latest_message": "Nenhuma atualização disponível! Você está na versão mais recente.",
"current_version": "Versão Atual"
"current_version": "Versão Atual",
"download_zip_file": "Baixar arquivo ZIP",
"unzipping_package": "Descompactando o pacote",
"copying_files": "Copiando arquivos",
"running_migrations": "Executando migrações",
"finishing_update": "Atualização de acabamento",
"update_failed": "Atualização falhou",
"update_failed_text": "Desculpa! Sua atualização falhou em: {step} step"
}
},
"wizard": {
@ -878,4 +886,4 @@
"ref_number_maxlength": "O número de referência não deve ter mais que 255 caracteres.",
"prefix_maxlength": "O prefixo não deve ter mais que 5 caracteres."
}
}
}

View File

@ -21,13 +21,6 @@ export const login = ({ commit, dispatch, state }, data) => {
window.toastr['success']('Login Successful')
resolve(response)
}).catch(err => {
if (err.response.data.error === 'invalid_credentials') {
window.toastr['error']('Invalid Credentials')
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', err.message)
}
commit(types.AUTH_ERROR, err.response)
Ls.remove('auth.token')
reject(err)

View File

@ -42,7 +42,6 @@ export default {
},
[types.ADD_ITEM_UNIT] (state, data) {
state.itemUnits.push(data.unit)
state.itemUnits = [data.unit, ...state.itemUnits]
},

View File

@ -40,7 +40,6 @@ export default {
},
[types.ADD_PAYMENT_MODE] (state, data) {
state.paymentModes.push(data.paymentMethod)
state.paymentModes = [data.paymentMethod, ...state.paymentModes]
},

View File

@ -46,7 +46,7 @@
</div>
</div>
<base-button type="submit" color="theme">{{ $t('login.login') }}</base-button>
<base-button :loading="isLoading" type="submit" color="theme">{{ $t('login.login') }}</base-button>
<!-- <div class="social-links">
@ -87,7 +87,8 @@ export default {
password: '',
remember: ''
},
submitted: false
submitted: false,
isLoading: false
}
},
validations: {
@ -98,7 +99,7 @@ export default {
},
password: {
required,
minLength: minLength(5)
minLength: minLength(8)
}
}
},
@ -113,7 +114,6 @@ export default {
}
this.isLoading = true
this.login(this.loginData).then((res) => {
this.$router.push('/admin/dashboard')
this.isLoading = false

View File

@ -4,16 +4,12 @@
<h3 class="page-title">{{ $t('estimates.title') }}</h3>
<ol class="breadcrumb">
<li class="breadcrumb-item">
<router-link
slot="item-title"
to="dashboard">
<router-link slot="item-title" to="dashboard">
{{ $t('general.home') }}
</router-link>
</li>
<li class="breadcrumb-item">
<router-link
slot="item-title"
to="#">
<router-link slot="item-title" to="#">
{{ $tc('estimates.estimate', 2) }}
</router-link>
</li>
@ -33,11 +29,9 @@
</base-button>
</div>
<router-link slot="item-title" class="col-xs-2" to="estimates/create">
<base-button
size="large"
icon="plus"
color="theme" >
{{ $t('estimates.new_estimate') }}</base-button>
<base-button size="large" icon="plus" color="theme">
{{ $t('estimates.new_estimate') }}</base-button
>
</router-link>
</div>
</div>
@ -46,7 +40,7 @@
<div v-show="showFilters" class="filter-section">
<div class="filter-container">
<div class="filter-customer">
<label>{{ $tc('customers.customer',1) }} </label>
<label>{{ $tc('customers.customer', 1) }} </label>
<base-customer-select
ref="customerSelect"
@select="onSelectCustomer"
@ -85,21 +79,28 @@
</div>
<div class="filter-estimate">
<label>{{ $t('estimates.estimate_number') }}</label>
<base-input
v-model="filters.estimate_number"
icon="hashtag"/>
<base-input v-model="filters.estimate_number" icon="hashtag" />
</div>
</div>
<label class="clear-filter" @click="clearFilter">{{ $t('general.clear_all') }}</label>
<label class="clear-filter" @click="clearFilter">{{
$t('general.clear_all')
}}</label>
</div>
</transition>
<div v-cloak v-show="showEmptyScreen" class="col-xs-1 no-data-info" align="center">
<moon-walker-icon class="mt-5 mb-4"/>
<div
v-cloak
v-show="showEmptyScreen"
class="col-xs-1 no-data-info"
align="center"
>
<moon-walker-icon class="mt-5 mb-4" />
<div class="row" align="center">
<label class="col title">{{ $t('estimates.no_estimates') }}</label>
</div>
<div class="row">
<label class="description col mt-1" align="center">{{ $t('estimates.list_of_estimates') }}</label>
<label class="description col mt-1" align="center">{{
$t('estimates.list_of_estimates')
}}</label>
</div>
<div class="btn-container">
<base-button
@ -116,28 +117,57 @@
<div v-show="!showEmptyScreen" class="table-container">
<div class="table-actions mt-5">
<p class="table-stats">{{ $t('general.showing') }}: <b>{{ estimates.length }}</b> {{ $t('general.of') }} <b>{{ totalEstimates }}</b></p>
<p class="table-stats">
{{ $t('general.showing') }}: <b>{{ estimates.length }}</b>
{{ $t('general.of') }} <b>{{ totalEstimates }}</b>
</p>
<!-- Tabs -->
<ul class="tabs">
<li class="tab" @click="getStatus('DRAFT')">
<a :class="['tab-link', {'a-active': filters.status === 'DRAFT'}]" href="#">{{ $t('general.draft') }}</a>
<a
:class="['tab-link', { 'a-active': filters.status === 'DRAFT' }]"
href="#"
>{{ $t('general.draft') }}</a
>
</li>
<li class="tab" @click="getStatus('SENT')">
<a :class="['tab-link', {'a-active': filters.status === 'SENT'}]" href="#" >{{ $t('general.sent') }}</a>
<a
:class="['tab-link', { 'a-active': filters.status === 'SENT' }]"
href="#"
>{{ $t('general.sent') }}</a
>
</li>
<li class="tab" @click="getStatus('')">
<a :class="['tab-link', {'a-active': filters.status === '' || filters.status !== 'DRAFT' && filters.status !== 'SENT'}]" href="#">{{ $t('general.all') }}</a>
<a
:class="[
'tab-link',
{
'a-active':
filters.status === '' ||
(filters.status !== 'DRAFT' && filters.status !== 'SENT'),
},
]"
href="#"
>{{ $t('general.all') }}</a
>
</li>
</ul>
<transition name="fade">
<v-dropdown v-if="selectedEstimates.length" :show-arrow="false">
<span slot="activator" href="#" class="table-actions-button dropdown-toggle">
<span
slot="activator"
href="#"
class="table-actions-button dropdown-toggle"
>
{{ $t('general.actions') }}
</span>
<v-dropdown-item>
<div class="dropdown-item" @click="removeMultipleEstimates">
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
<font-awesome-icon
:icon="['fas', 'trash']"
class="dropdown-item-icon"
/>
{{ $t('general.delete') }}
</div>
</v-dropdown-item>
@ -153,8 +183,12 @@
type="checkbox"
class="custom-control-input"
@change="selectAllEstimates"
/>
<label
v-show="!isRequestOngoing"
for="select-all"
class="custom-control-label selectall"
>
<label v-show="!isRequestOngoing" for="select-all" class="custom-control-label selectall">
<span class="select-all-label">{{ $t('general.select_all') }} </span>
</label>
</div>
@ -178,7 +212,7 @@
:value="row.id"
type="checkbox"
class="custom-control-input"
>
/>
<label :for="row.id" class="custom-control-label" />
</div>
</template>
@ -186,30 +220,30 @@
<table-column
:label="$t('estimates.date')"
sort-as="estimate_date"
show="formattedEstimateDate" />
show="formattedEstimateDate"
/>
<table-column
:label="$t('estimates.customer')"
sort-as="name"
show="name" />
show="name"
/>
<!-- <table-column
:label="$t('estimates.expiry_date')"
sort-as="expiry_date"
show="formattedExpiryDate" /> -->
<table-column
:label="$t('estimates.status')"
show="status" >
<template slot-scope="row" >
<table-column :label="$t('estimates.status')" show="status">
<template slot-scope="row">
<span> {{ $t('estimates.status') }}</span>
<span :class="'est-status-'+row.status.toLowerCase()">{{ row.status }}</span>
<span :class="'est-status-' + row.status.toLowerCase()">{{
row.status
}}</span>
</template>
</table-column>
<table-column
:label="$tc('estimates.estimate', 1)"
show="estimate_number"/>
<table-column
:label="$t('invoices.total')"
sort-as="total"
>
show="estimate_number"
/>
<table-column :label="$t('invoices.total')" sort-as="total">
<template slot-scope="row">
<span> {{ $t('estimates.total') }}</span>
<div v-html="$utils.formatMoney(row.total, row.user.currency)" />
@ -227,50 +261,114 @@
<dot-icon />
</a>
<v-dropdown-item>
<router-link :to="{path: `estimates/${row.id}/edit`}" class="dropdown-item">
<font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon" />
<router-link
:to="{ path: `estimates/${row.id}/edit` }"
class="dropdown-item"
>
<font-awesome-icon
:icon="['fas', 'pencil-alt']"
class="dropdown-item-icon"
/>
{{ $t('general.edit') }}
</router-link>
</v-dropdown-item>
<v-dropdown-item>
<div class="dropdown-item" @click="removeEstimate(row.id)">
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
<font-awesome-icon
:icon="['fas', 'trash']"
class="dropdown-item-icon"
/>
{{ $t('general.delete') }}
</div>
</v-dropdown-item>
<v-dropdown-item>
<router-link :to="{path: `estimates/${row.id}/view`}" class="dropdown-item">
<router-link
:to="{ path: `estimates/${row.id}/view` }"
class="dropdown-item"
>
<font-awesome-icon icon="eye" class="dropdown-item-icon" />
{{ $t('general.view') }}
</router-link>
</v-dropdown-item>
<v-dropdown-item>
<a class="dropdown-item" href="#/" @click="convertInToinvoice(row.id)">
<font-awesome-icon icon="file-alt" class="dropdown-item-icon" />
<a
class="dropdown-item"
href="#/"
@click="convertInToinvoice(row.id)"
>
<font-awesome-icon
icon="file-alt"
class="dropdown-item-icon"
/>
{{ $t('estimates.convert_to_invoice') }}
</a>
</v-dropdown-item>
<v-dropdown-item v-if="row.status !== 'SENT'">
<a class="dropdown-item" href="#/" @click.self="onMarkAsSent(row.id)">
<font-awesome-icon icon="check-circle" class="dropdown-item-icon" />
<a
class="dropdown-item"
href="#/"
@click.self="onMarkAsSent(row.id)"
>
<font-awesome-icon
icon="check-circle"
class="dropdown-item-icon"
/>
{{ $t('estimates.mark_as_sent') }}
</a>
</v-dropdown-item>
<v-dropdown-item v-if="row.status !== 'SENT'">
<a class="dropdown-item" href="#/" @click.self="sendEstimate(row.id)">
<font-awesome-icon icon="paper-plane" class="dropdown-item-icon" />
<v-dropdown-item v-if="row.status === 'DRAFT'">
<a
class="dropdown-item"
href="#/"
@click.self="sendEstimate(row.id)"
>
<font-awesome-icon
icon="paper-plane"
class="dropdown-item-icon"
/>
{{ $t('estimates.send_estimate') }}
</a>
</v-dropdown-item>
<!-- resend estimte -->
<v-dropdown-item
v-if="row.status == 'SENT' || row.status == 'VIEWED'"
>
<a
class="dropdown-item"
href="#/"
@click.self="sendEstimate(row.id)"
>
<font-awesome-icon
icon="paper-plane"
class="dropdown-item-icon"
/>
{{ $t('estimates.resend_estimate') }}
</a>
</v-dropdown-item>
<!-- -->
<v-dropdown-item v-if="row.status !== 'ACCEPTED'">
<a class="dropdown-item" href="#/" @click.self="onMarkAsAccepted(row.id)">
<font-awesome-icon icon="check-circle" class="dropdown-item-icon" />
<a
class="dropdown-item"
href="#/"
@click.self="onMarkAsAccepted(row.id)"
>
<font-awesome-icon
icon="check-circle"
class="dropdown-item-icon"
/>
{{ $t('estimates.mark_as_accepted') }}
</a>
</v-dropdown-item>
<v-dropdown-item v-if="row.status !== 'REJECTED'">
<a class="dropdown-item" href="#/" @click.self="onMarkAsRejected(row.id)">
<font-awesome-icon icon="times-circle" class="dropdown-item-icon" />
<a
class="dropdown-item"
href="#/"
@click.self="onMarkAsRejected(row.id)"
>
<font-awesome-icon
icon="times-circle"
class="dropdown-item-icon"
/>
{{ $t('estimates.mark_as_rejected') }}
</a>
</v-dropdown-item>

View File

@ -12,6 +12,7 @@
ref="baseSelect"
v-model="itemSelect"
:options="items"
:loading="loading"
:show-labels="false"
:preserve-search="true"
:initial-search="item.name"
@ -20,7 +21,7 @@
label="name"
class="multi-select-item"
@value="onTextChange"
@select="(val) => $emit('select', val)"
@select="onSelect"
>
<div slot="afterList">
<button type="button" class="list-add-button" @click="openItemModal">
@ -112,6 +113,7 @@ export default {
]),
async searchItems (search) {
let data = {
search,
filter: {
name: search,
unit: '',
@ -141,6 +143,10 @@ export default {
'data': {taxPerItem: this.taxPerItem, taxes: this.taxes}
})
},
onSelect(val) {
this.$emit('select', val)
this.fetchItems()
},
deselectItem () {
this.itemSelect = null
this.$emit('deselect')

View File

@ -1,7 +1,7 @@
<template>
<div v-if="estimate" class="main-content estimate-view-page">
<div class="page-header">
<h3 class="page-title"> {{ estimate.estimate_number }}</h3>
<h3 class="page-title">{{ estimate.estimate_number }}</h3>
<div class="page-actions row">
<div class="col-xs-2 mr-3">
<base-button
@ -26,19 +26,42 @@
{{ $t('estimates.send_estimate') }}
</base-button>
</div>
<v-dropdown :close-on-select="false" align="left" class="filter-container">
<v-dropdown
:close-on-select="true"
align="left"
class="filter-container"
>
<a slot="activator" href="#">
<base-button color="theme">
<font-awesome-icon icon="ellipsis-h" />
</base-button>
</a>
<v-dropdown-item>
<router-link :to="{path: `/admin/estimates/${$route.params.id}/edit`}" class="dropdown-item">
<font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon"/>
<div class="dropdown-item" @click="copyPdfUrl()">
<font-awesome-icon
:icon="['fas', 'link']"
class="dropdown-item-icon"
/>
{{ $t('general.copy_pdf_url') }}
</div>
<router-link
:to="{ path: `/admin/estimates/${$route.params.id}/edit` }"
class="dropdown-item"
>
<font-awesome-icon
:icon="['fas', 'pencil-alt']"
class="dropdown-item-icon"
/>
{{ $t('general.edit') }}
</router-link>
<div class="dropdown-item" @click="removeEstimate($route.params.id)">
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
<div
class="dropdown-item"
@click="removeEstimate($route.params.id)"
>
<font-awesome-icon
:icon="['fas', 'trash']"
class="dropdown-item-icon"
/>
{{ $t('general.delete') }}
</div>
</v-dropdown-item>
@ -57,14 +80,18 @@
align-icon="right"
@input="onSearched()"
/>
<div
class="btn-group ml-3"
role="group"
aria-label="First group"
<div class="btn-group ml-3" role="group" aria-label="First group">
<v-dropdown
:close-on-select="false"
align="left"
class="filter-container"
>
<v-dropdown :close-on-select="false" align="left" class="filter-container">
<a slot="activator" href="#">
<base-button class="inv-button inv-filter-fields-btn" color="default" size="medium">
<base-button
class="inv-button inv-filter-fields-btn"
color="default"
size="medium"
>
<font-awesome-icon icon="filter" />
</base-button>
</a>
@ -80,8 +107,10 @@
class="inv-radio"
value="estimate_date"
@change="onSearched"
>
<label class="inv-label" for="filter_estimate_date">{{ $t('reports.estimates.estimate_date') }}</label>
/>
<label class="inv-label" for="filter_estimate_date">{{
$t('reports.estimates.estimate_date')
}}</label>
</div>
<div class="filter-items">
<input
@ -92,8 +121,10 @@
class="inv-radio"
value="expiry_date"
@change="onSearched"
>
<label class="inv-label" for="filter_due_date">{{ $t('estimates.due_date') }}</label>
/>
<label class="inv-label" for="filter_due_date">{{
$t('estimates.due_date')
}}</label>
</div>
<div class="filter-items">
<input
@ -104,11 +135,19 @@
class="inv-radio"
value="estimate_number"
@change="onSearched"
>
<label class="inv-label" for="filter_estimate_number">{{ $t('estimates.estimate_number') }}</label>
/>
<label class="inv-label" for="filter_estimate_number">{{
$t('estimates.estimate_number')
}}</label>
</div>
</v-dropdown>
<base-button v-tooltip.top-center="{ content: getOrderName }" class="inv-button inv-filter-sorting-btn" color="default" size="medium" @click="sortData">
<base-button
v-tooltip.top-center="{ content: getOrderName }"
class="inv-button inv-filter-sorting-btn"
color="default"
size="medium"
@click="sortData"
>
<font-awesome-icon v-if="getOrderBy" icon="sort-amount-up" />
<font-awesome-icon v-else icon="sort-amount-down" />
</base-button>
@ -116,7 +155,7 @@
</div>
<div class="side-content">
<router-link
v-for="(estimate,index) in estimates"
v-for="(estimate, index) in estimates"
:to="`/admin/estimates/${estimate.id}/view`"
:key="index"
class="side-estimate"
@ -124,10 +163,20 @@
<div class="left">
<div class="inv-name">{{ estimate.user.name }}</div>
<div class="inv-number">{{ estimate.estimate_number }}</div>
<div :class="'est-status-'+estimate.status.toLowerCase()" class="inv-status">{{ estimate.status }}</div>
<div
:class="'est-status-' + estimate.status.toLowerCase()"
class="inv-status"
>
{{ estimate.status }}
</div>
</div>
<div class="right">
<div class="inv-amount" v-html="$utils.formatMoney(estimate.total, estimate.user.currency)" />
<div
class="inv-amount"
v-html="
$utils.formatMoney(estimate.total, estimate.user.currency)
"
/>
<div class="inv-date">{{ estimate.formattedEstimateDate }}</div>
</div>
</router-link>
@ -137,7 +186,7 @@
</div>
</div>
<div class="estimate-view-page-container">
<iframe :src="`${shareableLink}`" class="frame-style"/>
<iframe :src="`${shareableLink}`" class="frame-style" />
</div>
</div>
</template>
@ -289,6 +338,13 @@ export default {
}
})
},
copyPdfUrl () {
let pdfUrl = `${window.location.origin}/estimates/pdf/${this.estimate.unique_hash}`
let response = this.$utils.copyTextToClipboard(pdfUrl)
window.toastr['success'](this.$tc('Copied PDF url to clipboard!'))
},
async removeEstimate (id) {
window.swal({
title: 'Deleted',

View File

@ -102,6 +102,19 @@
<span v-if="!$v.formData.amount.minValue" class="text-danger">{{ $t('validation.price_minvalue') }}</span>
</div>
</div>
<div class="form-group col-sm-6">
<label class="form-label">{{ $t('expenses.customer') }}</label>
<base-select
ref="baseSelect"
v-model="customer"
:options="customerList"
:searchable="true"
:show-labels="false"
:placeholder="$t('customers.select_a_customer')"
label="name"
track-by="id"
/>
</div>
<div class="form-group col-sm-6">
<label for="description">{{ $t('expenses.note') }}</label>
<base-text-area
@ -169,7 +182,8 @@ export default {
expense_category_id: null,
expense_date: new Date(),
amount: null,
notes: ''
notes: '',
user_id: null
},
money: {
decimal: '.',
@ -185,7 +199,9 @@ export default {
passData: [],
contacts: [],
previewReceipt: null,
fileSendUrl: '/api/expenses'
fileSendUrl: '/api/expenses',
customer: null,
customerList: []
}
},
validations: {
@ -297,6 +313,8 @@ export default {
},
async fetchInitialData () {
this.fetchCategories()
let fetchData = await this.fetchCreateExpense()
this.customerList = fetchData.data.customers
if (this.isEdit) {
let response = await this.fetchExpense(this.$route.params.id)
this.category = response.data.expense.category
@ -304,6 +322,9 @@ export default {
this.formData.expense_date = moment(this.formData.expense_date).toString()
this.formData.amount = (response.data.expense.amount)
this.fileSendUrl = `/api/expenses/${this.$route.params.id}`
if (response.data.expense.user_id) {
this.customer = this.customerList.find(customer => customer.id === response.data.expense.user_id)
}
}
},
async sendData () {
@ -321,7 +342,8 @@ export default {
data.append('expense_category_id', this.formData.expense_category_id)
data.append('expense_date', moment(this.formData.expense_date).format('DD/MM/YYYY'))
data.append('amount', (this.formData.amount))
data.append('notes', this.formData.notes)
data.append('notes', this.formData.notes ? this.formData.notes : '')
data.append('user_id', this.customer ? this.customer.id : '')
if (this.isEdit) {
this.isLoading = true

View File

@ -43,7 +43,19 @@
<transition name="fade">
<div v-show="showFilters" class="filter-section">
<div class="row">
<div class="col-md-4">
<div class="col-md-3">
<label>{{ $t('expenses.customer') }}</label>
<base-select
v-model="filters.user"
:options="customers"
:searchable="true"
:show-labels="false"
:placeholder="$t('expenses.select_a_customer')"
label="name"
@click="filter = ! filter"
/>
</div>
<div class="col-md-3">
<label>{{ $t('expenses.category') }}</label>
<base-select
v-model="filters.category"
@ -55,7 +67,7 @@
@click="filter = ! filter"
/>
</div>
<div class="col-md-4">
<div class="col-md-3">
<label>{{ $t('expenses.from_date') }}</label>
<base-date-picker
v-model="filters.from_date"
@ -63,7 +75,7 @@
calendar-button-icon="calendar"
/>
</div>
<div class="col-md-4">
<div class="col-md-3">
<label>{{ $t('expenses.to_date') }}</label>
<base-date-picker
v-model="filters.to_date"
@ -161,6 +173,11 @@
sort-as="name"
show="category.name"
/>
<table-column
:label="$t('expenses.customer')"
sort-as="user_name"
show="user_name"
/>
<table-column
:label="$t('expenses.date')"
sort-as="expense_date"
@ -237,10 +254,12 @@ export default {
showFilters: false,
filtersApplied: false,
isRequestOngoing: true,
customers: [],
filters: {
category: null,
from_date: '',
to_date: ''
to_date: '',
user: ''
}
}
},
@ -308,6 +327,7 @@ export default {
]),
async fetchData ({ page, filter, sort }) {
let data = {
user_id: this.filters.user ? this.filters.user.id : null,
expense_category_id: this.filters.category !== null ? this.filters.category.id : '',
from_date: this.filters.from_date === '' ? this.filters.from_date : moment(this.filters.from_date).format('DD/MM/YYYY'),
to_date: this.filters.to_date === '' ? this.filters.to_date : moment(this.filters.to_date).format('DD/MM/YYYY'),
@ -318,6 +338,7 @@ export default {
this.isRequestOngoing = true
let response = await this.fetchExpenses(data)
this.customers = response.data.customers
this.isRequestOngoing = false
return {
@ -340,7 +361,8 @@ export default {
this.filters = {
category: null,
from_date: '',
to_date: ''
to_date: '',
user: null
}
this.$nextTick(() => {

View File

@ -1,19 +1,15 @@
<template>
<div class="invoice-index-page invoices main-content">
<div class="page-header">
<h3 class="page-title"> {{ $t('invoices.title') }}</h3>
<h3 class="page-title">{{ $t('invoices.title') }}</h3>
<ol class="breadcrumb">
<li class="breadcrumb-item">
<router-link
slot="item-title"
to="dashboard">
<router-link slot="item-title" to="dashboard">
{{ $t('general.home') }}
</router-link>
</li>
<li class="breadcrumb-item">
<router-link
slot="item-title"
to="#">
<router-link slot="item-title" to="#">
{{ $tc('invoices.invoice', 2) }}
</router-link>
</li>
@ -32,7 +28,11 @@
{{ $t('general.filter') }}
</base-button>
</div>
<router-link slot="item-title" class="col-xs-2" to="/admin/invoices/create">
<router-link
slot="item-title"
class="col-xs-2"
to="/admin/invoices/create"
>
<base-button size="large" icon="plus" color="theme">
{{ $t('invoices.new_invoice') }}
</base-button>
@ -44,7 +44,7 @@
<div v-show="showFilters" class="filter-section">
<div class="filter-container">
<div class="filter-customer">
<label>{{ $tc('customers.customer',1) }} </label>
<label>{{ $tc('customers.customer', 1) }} </label>
<base-customer-select
ref="customerSelect"
@select="onSelectCustomer"
@ -88,22 +88,29 @@
</div>
<div class="filter-invoice">
<label>{{ $t('invoices.invoice_number') }}</label>
<base-input
v-model="filters.invoice_number"
icon="hashtag"/>
<base-input v-model="filters.invoice_number" icon="hashtag" />
</div>
</div>
<label class="clear-filter" @click="clearFilter">{{ $t('general.clear_all') }}</label>
<label class="clear-filter" @click="clearFilter">{{
$t('general.clear_all')
}}</label>
</div>
</transition>
<div v-cloak v-show="showEmptyScreen" class="col-xs-1 no-data-info" align="center">
<moon-walker-icon class="mt-5 mb-4"/>
<div
v-cloak
v-show="showEmptyScreen"
class="col-xs-1 no-data-info"
align="center"
>
<moon-walker-icon class="mt-5 mb-4" />
<div class="row" align="center">
<label class="col title">{{ $t('invoices.no_invoices') }}</label>
</div>
<div class="row">
<label class="description col mt-1" align="center">{{ $t('invoices.list_of_invoices') }}</label>
<label class="description col mt-1" align="center">{{
$t('invoices.list_of_invoices')
}}</label>
</div>
<div class="btn-container">
<base-button
@ -120,28 +127,65 @@
<div v-show="!showEmptyScreen" class="table-container">
<div class="table-actions mt-5">
<p class="table-stats">{{ $t('general.showing') }}: <b>{{ invoices.length }}</b> {{ $t('general.of') }} <b>{{ totalInvoices }}</b></p>
<p class="table-stats">
{{ $t('general.showing') }}: <b>{{ invoices.length }}</b>
{{ $t('general.of') }} <b>{{ totalInvoices }}</b>
</p>
<!-- Tabs -->
<ul class="tabs">
<li class="tab" @click="getStatus('UNPAID')">
<a :class="['tab-link', {'a-active': filters.status.value === 'UNPAID'}]" href="#" >{{ $t('general.due') }}</a>
<a
:class="[
'tab-link',
{ 'a-active': filters.status.value === 'UNPAID' },
]"
href="#"
>{{ $t('general.due') }}</a
>
</li>
<li class="tab" @click="getStatus('DRAFT')">
<a :class="['tab-link', {'a-active': filters.status.value === 'DRAFT'}]" href="#">{{ $t('general.draft') }}</a>
<a
:class="[
'tab-link',
{ 'a-active': filters.status.value === 'DRAFT' },
]"
href="#"
>{{ $t('general.draft') }}</a
>
</li>
<li class="tab" @click="getStatus('')">
<a :class="['tab-link', {'a-active': filters.status.value === '' || filters.status.value === null || filters.status.value !== 'DRAFT' && filters.status.value !== 'UNPAID'}]" href="#">{{ $t('general.all') }}</a>
<a
:class="[
'tab-link',
{
'a-active':
filters.status.value === '' ||
filters.status.value === null ||
(filters.status.value !== 'DRAFT' &&
filters.status.value !== 'UNPAID'),
},
]"
href="#"
>{{ $t('general.all') }}</a
>
</li>
</ul>
<transition name="fade">
<v-dropdown v-if="selectedInvoices.length" :show-arrow="false">
<span slot="activator" href="#" class="table-actions-button dropdown-toggle">
<span
slot="activator"
href="#"
class="table-actions-button dropdown-toggle"
>
{{ $t('general.actions') }}
</span>
<v-dropdown-item>
<div class="dropdown-item" @click="removeMultipleInvoices">
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
<font-awesome-icon
:icon="['fas', 'trash']"
class="dropdown-item-icon"
/>
{{ $t('general.delete') }}
</div>
</v-dropdown-item>
@ -155,8 +199,12 @@
type="checkbox"
class="custom-control-input"
@change="selectAllInvoices"
/>
<label
v-show="!isRequestOngoing"
for="select-all"
class="custom-control-label selectall"
>
<label v-show="!isRequestOngoing" for="select-all" class="custom-control-label selectall">
<span class="select-all-label">{{ $t('general.select_all') }} </span>
</label>
</div>
@ -180,8 +228,8 @@
:value="row.id"
type="checkbox"
class="custom-control-input"
>
<label :for="row.id" class="custom-control-label"/>
/>
<label :for="row.id" class="custom-control-label" />
</div>
</template>
</table-column>
@ -195,35 +243,33 @@
width="20%"
show="name"
/>
<table-column
:label="$t('invoices.status')"
sort-as="status"
>
<template slot-scope="row" >
<table-column :label="$t('invoices.status')" sort-as="status">
<template slot-scope="row">
<span> {{ $t('invoices.status') }}</span>
<span :class="'inv-status-'+row.status.toLowerCase()">{{ (row.status != 'PARTIALLY_PAID')? row.status : row.status.replace('_', ' ') }}</span>
<span :class="'inv-status-' + row.status.toLowerCase()">{{
row.status != 'PARTIALLY_PAID'
? row.status
: row.status.replace('_', ' ')
}}</span>
</template>
</table-column>
<table-column
:label="$t('invoices.paid_status')"
sort-as="paid_status"
>
<table-column :label="$t('invoices.paid_status')" sort-as="paid_status">
<template slot-scope="row">
<span>{{ $t('invoices.paid_status') }}</span>
<span :class="'inv-status-'+row.paid_status.toLowerCase()">{{ (row.paid_status != 'PARTIALLY_PAID')? row.paid_status : row.paid_status.replace('_', ' ') }}</span>
<span :class="'inv-status-' + row.paid_status.toLowerCase()">{{
row.paid_status != 'PARTIALLY_PAID'
? row.paid_status
: row.paid_status.replace('_', ' ')
}}</span>
</template>
</table-column>
<table-column
:label="$t('invoices.number')"
show="invoice_number"
/>
<table-column
:label="$t('invoices.amount_due')"
sort-as="due_amount"
>
<table-column :label="$t('invoices.number')" show="invoice_number" />
<table-column :label="$t('invoices.amount_due')" sort-as="due_amount">
<template slot-scope="row">
<span>{{ $t('invoices.amount_due') }}</span>
<div v-html="$utils.formatMoney(row.due_amount, row.user.currency)"/>
<div
v-html="$utils.formatMoney(row.due_amount, row.user.currency)"
/>
</template>
</table-column>
<table-column
@ -238,42 +284,91 @@
<dot-icon />
</a>
<v-dropdown-item>
<router-link :to="{path: `invoices/${row.id}/edit`}" class="dropdown-item">
<font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon"/>
<router-link
:to="{ path: `invoices/${row.id}/edit` }"
class="dropdown-item"
>
<font-awesome-icon
:icon="['fas', 'pencil-alt']"
class="dropdown-item-icon"
/>
{{ $t('general.edit') }}
</router-link>
<router-link :to="{path: `invoices/${row.id}/view`}" class="dropdown-item">
<router-link
:to="{ path: `invoices/${row.id}/view` }"
class="dropdown-item"
>
<font-awesome-icon icon="eye" class="dropdown-item-icon" />
{{ $t('invoices.view') }}
</router-link>
</v-dropdown-item>
<v-dropdown-item v-if="row.status == 'DRAFT'">
<a class="dropdown-item" href="#/" @click="sendInvoice(row.id)" >
<font-awesome-icon icon="paper-plane" class="dropdown-item-icon" />
<a class="dropdown-item" href="#/" @click="sendInvoice(row.id)">
<font-awesome-icon
icon="paper-plane"
class="dropdown-item-icon"
/>
{{ $t('invoices.send_invoice') }}
</a>
</v-dropdown-item>
<v-dropdown-item
v-if="row.status === 'SENT' || row.status === 'VIEWED'"
>
<a class="dropdown-item" href="#/" @click="sendInvoice(row.id)">
<font-awesome-icon
icon="paper-plane"
class="dropdown-item-icon"
/>
{{ $t('invoices.resend_invoice') }}
</a>
</v-dropdown-item>
<v-dropdown-item v-if="row.status == 'DRAFT'">
<a class="dropdown-item" href="#/" @click="markInvoiceAsSent(row.id)">
<font-awesome-icon icon="check-circle" class="dropdown-item-icon" />
<a
class="dropdown-item"
href="#/"
@click="markInvoiceAsSent(row.id)"
>
<font-awesome-icon
icon="check-circle"
class="dropdown-item-icon"
/>
{{ $t('invoices.mark_as_sent') }}
</a>
</v-dropdown-item>
<v-dropdown-item v-if="row.status === 'SENT' || row.status === 'VIEWED' || row.status === 'OVERDUE'">
<router-link :to="`/admin/payments/${row.id}/create`" class="dropdown-item">
<font-awesome-icon :icon="['fas', 'credit-card']" class="dropdown-item-icon"/>
<v-dropdown-item
v-if="
row.status === 'SENT' ||
row.status === 'VIEWED' ||
row.status === 'OVERDUE'
"
>
<router-link
:to="`/admin/payments/${row.id}/create`"
class="dropdown-item"
>
<font-awesome-icon
:icon="['fas', 'credit-card']"
class="dropdown-item-icon"
/>
{{ $t('payments.record_payment') }}
</router-link>
</v-dropdown-item>
<v-dropdown-item>
<a class="dropdown-item" href="#/" @click="onCloneInvoice(row.id)">
<a
class="dropdown-item"
href="#/"
@click="onCloneInvoice(row.id)"
>
<font-awesome-icon icon="copy" class="dropdown-item-icon" />
{{ $t('invoices.clone_invoice') }}
</a>
</v-dropdown-item>
<v-dropdown-item>
<div class="dropdown-item" @click="removeInvoice(row.id)">
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
<font-awesome-icon
:icon="['fas', 'trash']"
class="dropdown-item-icon"
/>
{{ $t('general.delete') }}
</div>
</v-dropdown-item>

View File

@ -12,6 +12,7 @@
ref="baseSelect"
v-model="itemSelect"
:options="items"
:loading="loading"
:show-labels="false"
:preserve-search="true"
:initial-search="item.name"
@ -20,7 +21,7 @@
label="name"
class="multi-select-item"
@value="onTextChange"
@select="(val) => $emit('select', val)"
@select="onSelect"
>
<div slot="afterList">
<button type="button" class="list-add-button" @click="openItemModal">
@ -101,6 +102,7 @@ export default {
]),
async searchItems (search) {
let data = {
search,
filter: {
name: search,
unit: '',
@ -130,6 +132,10 @@ export default {
'data': {taxPerItem: this.taxPerItem, taxes: this.taxes}
})
},
onSelect(val) {
this.$emit('select', val)
this.fetchItems()
},
deselectItem () {
this.itemSelect = null
this.$emit('deselect')

View File

@ -1,7 +1,7 @@
<template>
<div v-if="invoice" class="main-content invoice-view-page">
<div class="page-header">
<h3 class="page-title"> {{ invoice.invoice_number }}</h3>
<h3 class="page-title">{{ invoice.invoice_number }}</h3>
<div class="page-actions row">
<div class="col-xs-2 mr-3">
<base-button
@ -24,26 +24,47 @@
>
{{ $t('invoices.send_invoice') }}
</base-button>
<router-link v-if="invoice.status === 'SENT'" :to="`/admin/payments/${$route.params.id}/create`">
<base-button
color="theme"
<router-link
v-if="invoice.status === 'SENT'"
:to="`/admin/payments/${$route.params.id}/create`"
>
<base-button color="theme">
{{ $t('payments.record_payment') }}
</base-button>
</router-link>
<v-dropdown :close-on-select="false" align="left" class="filter-container">
<v-dropdown
:close-on-select="true"
align="left"
class="filter-container"
>
<a slot="activator" href="#">
<base-button color="theme">
<font-awesome-icon icon="ellipsis-h" />
</base-button>
</a>
<v-dropdown-item>
<router-link :to="{path: `/admin/invoices/${$route.params.id}/edit`}" class="dropdown-item">
<font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon"/>
<div class="dropdown-item" @click="copyPdfUrl">
<font-awesome-icon
:icon="['fas', 'link']"
class="dropdown-item-icon"
/>
{{ $t('general.copy_pdf_url') }}
</div>
<router-link
:to="{ path: `/admin/invoices/${$route.params.id}/edit` }"
class="dropdown-item"
>
<font-awesome-icon
:icon="['fas', 'pencil-alt']"
class="dropdown-item-icon"
/>
{{ $t('general.edit') }}
</router-link>
<div class="dropdown-item" @click="removeInvoice($route.params.id)">
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
<font-awesome-icon
:icon="['fas', 'trash']"
class="dropdown-item-icon"
/>
{{ $t('general.delete') }}
</div>
</v-dropdown-item>
@ -61,14 +82,18 @@
align-icon="right"
@input="onSearch"
/>
<div
class="btn-group ml-3"
role="group"
aria-label="First group"
<div class="btn-group ml-3" role="group" aria-label="First group">
<v-dropdown
:close-on-select="false"
align="left"
class="filter-container"
>
<v-dropdown :close-on-select="false" align="left" class="filter-container">
<a slot="activator" href="#">
<base-button class="inv-button inv-filter-fields-btn" color="default" size="medium">
<base-button
class="inv-button inv-filter-fields-btn"
color="default"
size="medium"
>
<font-awesome-icon icon="filter" />
</base-button>
</a>
@ -84,8 +109,10 @@
class="inv-radio"
value="invoice_date"
@change="onSearch"
>
<label class="inv-label" for="filter_invoice_date">{{ $t('invoices.invoice_date') }}</label>
/>
<label class="inv-label" for="filter_invoice_date">{{
$t('invoices.invoice_date')
}}</label>
</div>
<div class="filter-items">
<input
@ -96,8 +123,10 @@
class="inv-radio"
value="due_date"
@change="onSearch"
>
<label class="inv-label" for="filter_due_date">{{ $t('invoices.due_date') }}</label>
/>
<label class="inv-label" for="filter_due_date">{{
$t('invoices.due_date')
}}</label>
</div>
<div class="filter-items">
<input
@ -108,11 +137,19 @@
class="inv-radio"
value="invoice_number"
@change="onSearch"
>
<label class="inv-label" for="filter_invoice_number">{{ $t('invoices.invoice_number') }}</label>
/>
<label class="inv-label" for="filter_invoice_number">{{
$t('invoices.invoice_number')
}}</label>
</div>
</v-dropdown>
<base-button v-tooltip.top-center="{ content: getOrderName }" class="inv-button inv-filter-sorting-btn" color="default" size="medium" @click="sortData">
<base-button
v-tooltip.top-center="{ content: getOrderName }"
class="inv-button inv-filter-sorting-btn"
color="default"
size="medium"
@click="sortData"
>
<font-awesome-icon v-if="getOrderBy" icon="sort-amount-up" />
<font-awesome-icon v-else icon="sort-amount-down" />
</base-button>
@ -121,7 +158,7 @@
<base-loader v-if="isSearching" />
<div v-else class="side-content">
<router-link
v-for="(invoice,index) in invoices"
v-for="(invoice, index) in invoices"
:to="`/admin/invoices/${invoice.id}/view`"
:key="index"
class="side-invoice"
@ -129,10 +166,20 @@
<div class="left">
<div class="inv-name">{{ invoice.user.name }}</div>
<div class="inv-number">{{ invoice.invoice_number }}</div>
<div :class="'inv-status-'+invoice.status.toLowerCase()" class="inv-status">{{ invoice.status }}</div>
<div
:class="'inv-status-' + invoice.status.toLowerCase()"
class="inv-status"
>
{{ invoice.status }}
</div>
</div>
<div class="right">
<div class="inv-amount" v-html="$utils.formatMoney(invoice.due_amount, invoice.user.currency)" />
<div
class="inv-amount"
v-html="
$utils.formatMoney(invoice.due_amount, invoice.user.currency)
"
/>
<div class="inv-date">{{ invoice.formattedInvoiceDate }}</div>
</div>
</router-link>
@ -141,8 +188,8 @@
</p>
</div>
</div>
<div class="invoice-view-page-container" >
<iframe :src="`${shareableLink}`" class="frame-style"/>
<div class="invoice-view-page-container">
<iframe :src="`${shareableLink}`" class="frame-style" />
</div>
</div>
</template>
@ -291,6 +338,14 @@ export default {
}
})
},
copyPdfUrl () {
let pdfUrl = `${window.location.origin}/invoices/pdf/${this.invoice.unique_hash}`
let response = this.$utils.copyTextToClipboard(pdfUrl)
window.toastr['success'](this.$tc('Copied PDF url to clipboard!'))
},
async removeInvoice (id) {
this.selectInvoice([parseInt(id)])
this.id = id

View File

@ -1,7 +1,7 @@
<template>
<div v-if="payment" class="main-content payment-view-page">
<div class="page-header">
<h3 class="page-title"> {{ payment.payment_number }}</h3>
<h3 class="page-title">{{ payment.payment_number }}</h3>
<div class="page-actions row">
<base-button
:loading="isSendingEmail"
@ -11,19 +11,39 @@
>
{{ $t('payments.send_payment_receipt') }}
</base-button>
<v-dropdown :close-on-select="false" align="left" class="filter-container">
<v-dropdown
:close-on-select="true"
align="left"
class="filter-container"
>
<a slot="activator" href="#">
<base-button color="theme">
<font-awesome-icon icon="ellipsis-h" />
</base-button>
</a>
<v-dropdown-item>
<router-link :to="{path: `/admin/payments/${$route.params.id}/edit`}" class="dropdown-item">
<font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon"/>
<div class="dropdown-item" @click="copyPdfUrl">
<font-awesome-icon
:icon="['fas', 'link']"
class="dropdown-item-icon"
/>
{{ $t('general.copy_pdf_url') }}
</div>
<router-link
:to="{ path: `/admin/payments/${$route.params.id}/edit` }"
class="dropdown-item"
>
<font-awesome-icon
:icon="['fas', 'pencil-alt']"
class="dropdown-item-icon"
/>
{{ $t('general.edit') }}
</router-link>
<div class="dropdown-item" @click="removePayment($route.params.id)">
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
<font-awesome-icon
:icon="['fas', 'trash']"
class="dropdown-item-icon"
/>
{{ $t('general.delete') }}
</div>
</v-dropdown-item>
@ -41,14 +61,18 @@
align-icon="right"
@input="onSearch"
/>
<div
class="btn-group ml-3"
role="group"
aria-label="First group"
<div class="btn-group ml-3" role="group" aria-label="First group">
<v-dropdown
:close-on-select="false"
align="left"
class="filter-container"
>
<v-dropdown :close-on-select="false" align="left" class="filter-container">
<a slot="activator" href="#">
<base-button class="inv-button inv-filter-fields-btn" color="default" size="medium">
<base-button
class="inv-button inv-filter-fields-btn"
color="default"
size="medium"
>
<font-awesome-icon icon="filter" />
</base-button>
</a>
@ -64,8 +88,10 @@
class="inv-radio"
value="invoice_number"
@change="onSearch"
>
<label class="inv-label" for="filter_invoice_number">{{ $t('invoices.title') }}</label>
/>
<label class="inv-label" for="filter_invoice_number">{{
$t('invoices.title')
}}</label>
</div>
<div class="filter-items">
<input
@ -76,8 +102,10 @@
class="inv-radio"
value="payment_date"
@change="onSearch"
>
<label class="inv-label" for="filter_payment_date">{{ $t('payments.date') }}</label>
/>
<label class="inv-label" for="filter_payment_date">{{
$t('payments.date')
}}</label>
</div>
<div class="filter-items">
<input
@ -88,11 +116,19 @@
class="inv-radio"
value="payment_number"
@change="onSearch"
>
<label class="inv-label" for="filter_payment_number">{{ $t('payments.payment_number') }}</label>
/>
<label class="inv-label" for="filter_payment_number">{{
$t('payments.payment_number')
}}</label>
</div>
</v-dropdown>
<base-button v-tooltip.top-center="{ content: getOrderName }" class="inv-button inv-filter-sorting-btn" color="default" size="medium" @click="sortData">
<base-button
v-tooltip.top-center="{ content: getOrderName }"
class="inv-button inv-filter-sorting-btn"
color="default"
size="medium"
@click="sortData"
>
<font-awesome-icon v-if="getOrderBy" icon="sort-amount-up" />
<font-awesome-icon v-else icon="sort-amount-down" />
</base-button>
@ -101,7 +137,7 @@
<base-loader v-if="isSearching" />
<div v-else class="side-content">
<router-link
v-for="(payment,index) in payments"
v-for="(payment, index) in payments"
:to="`/admin/payments/${payment.id}/view`"
:key="index"
class="side-payment"
@ -112,7 +148,10 @@
<div class="inv-number">{{ payment.invoice_number }}</div>
</div>
<div class="right">
<div class="inv-amount" v-html="$utils.formatMoney(payment.amount, payment.user.currency)" />
<div
class="inv-amount"
v-html="$utils.formatMoney(payment.amount, payment.user.currency)"
/>
<div class="inv-date">{{ payment.formattedPaymentDate }}</div>
<!-- <div class="inv-number">{{ payment.payment_method.name }}</div> -->
</div>
@ -122,8 +161,8 @@
</p>
</div>
</div>
<div class="payment-view-page-container" >
<iframe :src="`${shareableLink}`" class="frame-style"/>
<div class="payment-view-page-container">
<iframe :src="`${shareableLink}`" class="frame-style" />
</div>
</div>
</template>
@ -260,6 +299,13 @@ export default {
}
})
},
copyPdfUrl () {
let pdfUrl = `${window.location.origin}/payments/pdf/${this.payment.unique_hash}`
let response = this.$utils.copyTextToClipboard(pdfUrl)
window.toastr['success'](this.$tc('Copied PDF url to clipboard!'))
},
async removePayment (id) {
this.id = id
window.swal({

View File

@ -1,33 +1,76 @@
<template>
<div class="setting-main-container">
<div class="setting-main-container update-container">
<div class="card setting-card">
<div class="page-header">
<h3 class="page-title">{{ $t('settings.update_app.title') }}</h3>
<p class="page-sub-title">
{{ $t('settings.update_app.description') }}
</p>
<label class="input-label">{{ $t('settings.update_app.current_version') }}</label><br>
<label class="input-label">{{
$t('settings.update_app.current_version')
}}</label
><br />
<label class="version mb-4">{{ currentVersion }}</label>
<base-button :outline="true" :disabled="isCheckingforUpdate || isUpdating" size="large" color="theme" class="mb-4" @click="checkUpdate">
<font-awesome-icon :class="{'update': isCheckingforUpdate}" style="margin-right: 10px;" icon="sync-alt" />
<base-button
:outline="true"
:disabled="isCheckingforUpdate || isUpdating"
size="large"
color="theme"
class="mb-4"
@click="checkUpdate"
>
<font-awesome-icon
:class="{ update: isCheckingforUpdate }"
style="margin-right: 10px;"
icon="sync-alt"
/>
{{ $t('settings.update_app.check_update') }}
</base-button>
<hr>
<hr />
<div v-show="!isUpdating" v-if="isUpdateAvailable" class="mt-4 content">
<h3 class="page-title mb-3">{{ $t('settings.update_app.avail_update') }}</h3>
<label class="input-label">{{ $t('settings.update_app.next_version') }}</label><br>
<h3 class="page-title mb-3">
{{ $t('settings.update_app.avail_update') }}
</h3>
<label class="input-label">{{
$t('settings.update_app.next_version')
}}</label
><br />
<label class="version">{{ updateData.version }}</label>
<p class="page-sub-title" style="white-space: pre-wrap;">{{ description }}</p>
<base-button size="large" icon="rocket" color="theme" @click="onUpdateApp">
<base-button
size="large"
icon="rocket"
color="theme"
@click="onUpdateApp"
>
{{ $t('settings.update_app.update') }}
</base-button>
</div>
<div v-if="isUpdating" class="mt-4 content">
<h3 class="page-title">{{ $t('settings.update_app.update_progress') }}</h3>
<div class="d-flex flex-row justify-content-between">
<div>
<h3 class="page-title">
{{ $t('settings.update_app.update_progress') }}
</h3>
<p class="page-sub-title">
{{ $t('settings.update_app.progress_text') }}
</p>
<font-awesome-icon icon="spinner" class="fa-spin"/>
</div>
<font-awesome-icon icon="spinner" class="update-spinner fa-spin" />
</div>
<ul class="update-steps-container">
<li class="update-step" v-for="step in updateSteps">
<p class="update-step-text">{{ $t(step.translationKey) }}</p>
<div class="update-status-container">
<span v-if="step.time" class="update-time">{{
step.time
}}</span>
<span :class="'update-status status-' + getStatus(step)">{{
getStatus(step)
}}</span>
</div>
</li>
</ul>
</div>
</div>
</div>
@ -36,7 +79,7 @@
<script>
export default {
data () {
data() {
return {
isShowProgressBar: false,
isUpdateAvailable: false,
@ -46,60 +89,78 @@ export default {
interval: null,
description: '',
currentVersion: '',
updateSteps: [
{
translationKey: 'settings.update_app.download_zip_file',
stepUrl: '/api/update/download',
time: null,
started: false,
completed: false,
},
{
translationKey: 'settings.update_app.unzipping_package',
stepUrl: '/api/update/unzip',
time: null,
started: false,
completed: false,
},
{
translationKey: 'settings.update_app.copying_files',
stepUrl: '/api/update/copy',
time: null,
started: false,
completed: false,
},
{
translationKey: 'settings.update_app.running_migrations',
stepUrl: '/api/update/migrate',
time: null,
started: false,
completed: false,
},
{
translationKey: 'settings.update_app.finishing_update',
stepUrl: '/api/update/finish',
time: null,
started: false,
completed: false,
},
],
updateData: {
isMinor: Boolean,
installed: '',
version: ''
}
version: '',
},
}
},
created () {
created() {
window.addEventListener('beforeunload', (event) => {
if (this.isUpdating) {
event.returnValue = 'Update is in progress!'
}
})
},
mounted () {
mounted() {
window.axios.get('/api/settings/app/version').then((res) => {
this.currentVersion = res.data.version
})
},
methods: {
closeHandler () {
closeHandler() {
console.log('closing')
},
async onUpdateApp () {
try {
this.isUpdating = true
this.updateData.installed = this.currentVersion
let res = await window.axios.post('/api/update', this.updateData)
if (res.data.success) {
setTimeout(async () => {
await window.axios.post('/api/update/finish', this.updateData)
window.toastr['success'](this.$t('settings.update_app.update_success'))
this.currentVersion = this.updateData.version
this.isUpdateAvailable = false
setTimeout(() => {
location.reload()
}, 2000)
}, 1000)
getStatus(step) {
if (step.started && step.completed) {
return 'finished'
} else if (step.started && !step.completed) {
return 'running'
} else if (!step.started && !step.completed) {
return 'pending'
} else {
console.log(res.data)
window.toastr['error'](res.data.error)
return 'error'
}
} catch (e) {
console.log(e)
window.toastr['error']('Something went wrong')
}
this.isUpdating = false
},
async checkUpdate () {
async checkUpdate() {
try {
this.isCheckingforUpdate = true
let response = await window.axios.get('/api/check/update')
@ -122,8 +183,67 @@ export default {
this.isCheckingforUpdate = false
window.toastr['error']('Something went wrong')
}
},
async onUpdateApp() {
let path = null
for (let index = 0; index < this.updateSteps.length; index++) {
let currentStep = this.updateSteps[index]
try {
this.isUpdating = true
currentStep.started = true
let updateParams = {
version: this.updateData.version,
installed: this.currentVersion,
path: path || null,
}
let requestResponse = await window.axios.post(
currentStep.stepUrl,
updateParams
)
currentStep.completed = true
if (requestResponse.data && requestResponse.data.path) {
path = requestResponse.data.path
}
// on finish
if (
currentStep.translationKey == 'settings.update_app.finishing_update'
) {
this.isUpdating = false
window.toastr['success'](
this.$t('settings.update_app.update_success')
)
setTimeout(() => {
location.reload()
}, 3000)
}
} catch (error) {
currentStep.started = false
currentStep.completed = true
window.toastr['error'](this.$t('validation.something_went_wrong'))
this.onUpdateFailed(currentStep.translationKey)
return false
}
}
},
onUpdateFailed(translationKey) {
let stepName = this.$t(translationKey)
swal({
title: this.$t('settings.update_app.update_failed'),
text: this.$tc('settings.update_app.update_failed_text', stepName, {step: stepName}),
buttons: [this.$t('general.cancel'), this.$t('general.retry')],
}).then(async (value) => {
if (value) {
this.onUpdateApp()
return
}
this.isUpdating = false
})
},
},
}
</script>

View File

@ -54,7 +54,8 @@ import {
faEyeSlash,
faSyncAlt,
faRocket,
faCamera
faCamera,
faLink,
} from '@fortawesome/free-solid-svg-icons'
import { far } from '@fortawesome/free-regular-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
@ -119,7 +120,8 @@ library.add(
faPaperPlane,
faSyncAlt,
faRocket,
faCamera
faCamera,
faLink
)
Vue.component('font-awesome-icon', FontAwesomeIcon)

View File

@ -27,6 +27,7 @@ fieldset[disabled] .multiselect {
top: 50%;
left: 50%;
margin: -8px 0 0 -8px;
z-index: 5;
width: 16px;
height: 16px;
border-radius: 100%;

View File

@ -122,6 +122,84 @@
}
.update-container {
.update-spinner {
font-size: 30px;
color: $ls-color-gray--dark;
}
.update-steps-container {
list-style-type: none;
width: 100%;
padding: 0px;
.update-step {
display: flex;
width: 100%;
justify-content: space-between;
padding: 10px 0px;
border-bottom: 1px solid $ls-color-gray--light;
&:last-child {
border-bottom: 0px solid;
}
}
}
.update-step-text {
font-size: $font-size-base;
margin: 0px;
line-height: 2rem;
}
.update-status-container {
display: flex;
flex-direction: row;
align-items: center;
.update-time {
font-size: 10px;
color: $ls-color-gray--dark;
margin-right: 10px;
}
.update-status {
font-size: 13px;
width: 88px;
height: 28px;
display: block;
text-align: center;
border-radius: 30px;
text-transform: uppercase;
line-height: 2rem;
}
.status-pending {
background-color: #EAF1FB;
color: $ls-color-secondary;
}
.status-running {
background-color: rgba(21, 178, 236, 0.15);
color: $ls-color-light-blue;
}
.status-finished {
background-color: #D4F6EE;
color: $ls-color-green;
}
.status-error {
background-color: rgba(251, 113, 120, 0.22);
color: $ls-color-red;
}
}
}
.add-new-tax {
height: 45px;
white-space: nowrap;

View File

@ -1,10 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>Estimate</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
/* -- Base -- */
body {
font-family: "DejaVu Sans";
}
@ -12,31 +14,22 @@
html {
margin: 0px;
padding: 0px;
margin-top: 50px;
}
table {
border-collapse: collapse;
}
.header-line {
color:rgba(0, 0, 0, 0.2);
position: absolute;
top: 90px;
left: 0px;
width: 100%;
}
hr {
margin: 0 30px 0 30px;
color:rgba(0, 0, 0, 0.2);
color: rgba(0, 0, 0, 0.2);
border: 0.5px solid #EAF1FB;
}
.header-center {
text-align: center
}
/* -- Header -- */
.header-table {
.header-container {
position: absolute;
width: 100%;
height: 90px;
@ -44,6 +37,14 @@
top: -50px;
}
.header-bottom-divider {
color: rgba(0, 0, 0, 0.2);
position: absolute;
top: 90px;
left: 0px;
width: 100%;
}
.header-logo {
height: 50px;
margin-top: 20px;
@ -51,32 +52,11 @@
color: #817AE3;
}
.inv-flex{
display:flex;
}
.inv-data{
text-align:right;
margin-right:120px;
}
.inv-value{
text-align:left;
margin-left:160px;
}
.header {
font-size: 20px;
color: rgba(0, 0, 0, 0.7);
}
.TextColor1 {
font-size: 16px;
color: rgba(0, 0, 0, 0.5);
}
@page {
margin-top: 60px !important;
}
.wrapper {
display: block;
margin-top: 0px;
@ -84,89 +64,83 @@
padding-bottom: 20px;
}
.address {
/* display: inline-block; */
padding-top: 30px
/* -- Company Details -- */
.company-details-container {
padding-top: 30px;
}
.company {
.company-address-container {
float: left;
padding-left: 30px;
font-weight: normal;
display: inline;
float:left;
width:30%;
width: 30%;
text-transform: capitalize;
margin-bottom: 2px;
}
.company h1 {
font-style: normal;
font-weight: normal;
.company-address-container {
padding-left: 30px;
float: left;
width: 30%;
text-transform: capitalize;
margin-bottom: 2px;
}
.company-address-container h1 {
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
margin-bottom: 0px;
margin-top: 10px;
}
.company-add {
.company-address {
margin-top: 2px;
text-align: left;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 15px;
color: #595959;
}
.job-add {
/* display: inline; */
.estimate-details-container {
float: right;
padding: 10px 30px 0 0;
}
.amount-due {
background-color: #f2f2f2;
}
.textRight {
text-align: right;
}
.textLeft {
text-align: left;
}
.textStyle1 {
font-style: normal;
font-weight: normal;
.attribute-label {
font-size: 12px;
line-height: 18px;
padding-right: 40px;
text-align: left;
color: #55547A
}
.textStyle2 {
font-style: normal;
font-weight: normal;
.attribute-value {
font-size: 12px;
line-height: 18px;
text-align: right;
}
.bill-add {
width:45%;
/* -- Customer Address -- */
.customer-address-container {
width: 45%;
padding: 0px 0 0 0px;
}
/* -------------------------- */
/* shipping style */
/* -- Shipping -- */
.ship-address-container {
.shipping-address-container {
float: right;
padding-left: 30px;
}
.ship-to {
font-style: normal;
font-weight: normal;
.shipping-address-container--left {
float: left;
padding-left: 0px;
}
.shipping-address-label {
font-size: 12px;
line-height: 18px;
padding: 0px;
@ -174,18 +148,15 @@
margin-bottom: 0px;
}
.ship-user-name {
max-width: 250px
font-style: normal;
font-weight: normal;
.shipping-address-name {
max-width: 160px;
font-size: 15px;
line-height: 22px;
padding: 0px;
margin: 0px;
}
.ship-user-address {
font-style: normal;
font-weight: normal;
.shipping-address {
font-size: 10px;
line-height: 15px;
color: #595959;
@ -193,27 +164,15 @@
margin: 0px;
width: 160px;
}
.ship-user-phone {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
padding: 0px;
margin: 0px;
}
/* -------------------------- */
/* billing style */
/* -- Billing -- */
.bill-address-container {
.billing-address-container {
float: left;
padding-left: 30px;
}
.bill-to {
font-style: normal;
font-weight: normal;
.billing-address-label {
font-size: 12px;
line-height: 18px;
padding: 0px;
@ -221,19 +180,15 @@
margin-bottom: 0px;
}
.bill-user-name {
max-width: 250px
font-style: normal;
font-weight: normal;
.billing-address-name {
max-width: 160px;
font-size: 15px;
line-height: 22px;
padding: 0px;
margin: 0px;
}
.bill-user-address {
font-style: normal;
font-weight: normal;
.billing-address {
font-size: 10px;
line-height: 15px;
color: #595959;
@ -242,28 +197,20 @@
width: 160px;
}
.bill-user-phone {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
padding: 0px;
margin: 0px;
}
/* -- Items Table -- */
.table2 {
.items-table {
margin-top: 35px;
padding: 0px 30px 10px 30px;
page-break-before: avoid;
page-break-after: auto;
}
.table2 hr {
height:0.1px;
.items-table hr {
height: 0.1px;
}
.ItemTableHeader {
.item-table-heading {
font-size: 13.5;
text-align: center;
color: rgba(0, 0, 0, 0.85);
@ -271,85 +218,86 @@
padding-bottom: 10px;
}
tr.main-table-header th {
tr.item-table-heading-row th {
border-bottom: 0.620315px solid #E8E8E8;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
}
.main-table-header {
.item-table-heading-row {
margin-bottom: 10px;
}
tr.item-details td {
font-style: normal;
font-weight: normal;
tr.item-row td {
font-size: 12px;
line-height: 18px;
}
.items {
.item-cell {
font-size: 13;
color: rgba(0, 0, 0, 0.6);
color: #040405;
text-align: center;
padding: 5px;
padding-top: 10px;
}
.padd8 {
padding-top: 8px;
padding-bottom: 8px;
}
.padd2 {
padding-top: 2px;
padding-bottom: 2px;
}
.table3 {
border-top: none;
box-sizing: border-box;
width: 630px;
page-break-inside: avoid;
page-break-before: auto;
page-break-after: auto;
}
.total-border-left {
border: 1px solid #E8E8E8!important;
border-right: 0px !important;
padding-top: 0px;
padding:8px !important;
}
.total-border-right {
border: 1px solid #E8E8E8!important;
border-left: 0px !important;
padding-top: 0px;
padding:8px !important;
}
.inv-item {
border-color: #d9d9d9;
}
.no-border {
border: none;
.item-description {
color: #595959;
font-size: 9px;
line-height: 12px;
}
.desc {
font-weight: 100;
text-align: justify;
font-size: 10px;
margin-bottom: 15px;
margin-top:7px;
color:rgba(0, 0, 0, 0.85);
/* -- Total Display Table -- */
.total-display-container {
padding: 0 25px;
}
.total-display-table {
border-top: none;
box-sizing: border-box;
page-break-inside: avoid;
page-break-before: auto;
page-break-after: auto;
margin-left: 500px;
margin-top: 20px;
}
.total-table-attribute-label {
font-size: 12px;
color: #55547A;
text-align: left;
padding-left: 10px;
}
.total-table-attribute-value {
font-weight: bold;
text-align: right;
font-size: 12px;
color: #040405;
padding-right: 10px;
padding-top: 2px;
padding-bottom: 2px;
}
.total-border-left {
border: 1px solid #E8E8E8 !important;
border-right: 0px !important;
padding-top: 0px;
padding: 8px !important;
}
.total-border-right {
border: 1px solid #E8E8E8 !important;
border-left: 0px !important;
padding-top: 0px;
padding: 8px !important;
}
/* -- Notes -- */
.notes {
font-style: normal;
font-weight: 300;
font-size: 12px;
color: #595959;
margin-top: 15px;
@ -360,8 +308,6 @@
}
.notes-label {
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
@ -371,13 +317,69 @@
padding-bottom: 10px;
}
/* -- Helpers -- */
.text-primary {
color: #5851DB;
}
.text-center {
text-align: center
}
table .text-left {
text-align: left;
}
table .text-right {
text-align: right;
}
.border-0 {
border: none;
}
.py-2 {
padding-top: 2px;
padding-bottom: 2px;
}
.py-8 {
padding-top: 8px;
padding-bottom: 8px;
}
.py-3 {
padding: 3px 0;
}
.pr-20 {
padding-right: 20px;
}
.pr-10 {
padding-right: 10px;
}
.pl-20 {
padding-left: 20px;
}
.pl-10 {
padding-left: 10px;
}
.pl-0 {
padding-left: 0;
}
</style>
</head>
<body>
<div class="header-table">
<div class="header-container">
<table width="100%">
<tr>
<td class="header-center">
<td class="text-center">
@if($logo)
<img class="header-logo" src="{{ $logo }}" alt="Company Logo">
@else
@ -388,39 +390,39 @@
</td>
</tr>
</table>
<hr class="header-line" />
<hr class="header-bottom-divider" />
</div>
<div class="wrapper">
<div class="address">
<div class="company">
<div class="company-details-container">
<div class="company-address-container">
@include('app.pdf.estimate.partials.company-address')
</div>
<div class="job-add">
<table>
<div class="estimate-details-container">
<table class="estimate-details-table">
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Estimate Number</td>
<td class="textStyle2"> &nbsp;{{$estimate->estimate_number}}</td>
<td class="attribute-label">Estimate Number</td>
<td class="attribute-value"> &nbsp;{{$estimate->estimate_number}}</td>
</tr>
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Estimate Date </td>
<td class="textStyle2"> &nbsp;{{$estimate->formattedEstimateDate}}</td>
<td class="attribute-label">Estimate Date </td>
<td class="attribute-value"> &nbsp;{{$estimate->formattedEstimateDate}}</td>
</tr>
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Expiry Date</td>
<td class="textStyle2"> &nbsp;{{$estimate->formattedExpiryDate}}</td>
<td class="attribute-label">Expiry Date</td>
<td class="attribute-value"> &nbsp;{{$estimate->formattedExpiryDate}}</td>
</tr>
</table>
</div>
<div style="clear: both;"></div>
</div>
<div class="bill-add">
<div class="bill-address-container">
<div class="customer-address-container">
<div class="billing-address-container">
@include('app.pdf.estimate.partials.billing-address')
</div>
@if($estimate->user->billingaddress)
<div class="ship-address-container">
<div class="shipping-address-container">
@else
<div class="ship-address-container " style="float:left;padding-left:0px;">
<div class="shipping-address-container--left">
@endif
@include('app.pdf.estimate.partials.shipping-address')
</div>
@ -432,4 +434,5 @@
@include('app.pdf.estimate.partials.notes')
</div>
</body>
</html>

View File

@ -1,9 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>Estimate</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
/* -- Base -- */
body {
font-family: "DejaVu Sans";
}
@ -11,22 +13,21 @@
html {
margin: 0px;
padding: 0px;
margin-top: 50px;
}
table {
border-collapse: collapse;
}
.header-left {
padding-top: 45px;
padding-bottom: 45px;
padding-left: 30px;
display:inline-block;
width:30%;
hr {
color: rgba(0, 0, 0, 0.2);
border: 0.5px solid #EAF1FB;
}
@page {
margin-top: 60px !important;
}
.header-table {
/* -- Header -- */
.header-container {
background: #817AE3;
position: absolute;
width: 100%;
@ -34,99 +35,129 @@
left: 0px;
top: -60px;
}
.header-section-left {
padding-top: 45px;
padding-bottom: 45px;
padding-left: 30px;
display: inline-block;
width: 30%;
}
.header-logo {
position: absolute;
height: 50px;
text-transform: capitalize;
color: #fff;
}
.header-right {
display:inline-block;
width:35%;
float:right;
.header-section-right {
display: inline-block;
width: 35%;
float: right;
padding: 20px 30px 20px 0px;
text-align: right;
color:white;
color: white;
}
}
.inv-flex{
display:flex;
}
.inv-data{
text-align:right;
margin-right:120px;
}
.inv-value{
text-align:left;
margin-left:160px;
}
.header {
font-size: 20px;
color: rgba(0, 0, 0, 0.7);
}
.TextColor1 {
font-size: 16px;
color: rgba(0, 0, 0, 0.5);
/* -- Estimate Details -- */
.estimate-details-container {
text-align: center;
width: 40%;
}
.estimate-details-container h1 {
margin: 0;
font-size: 24px;
line-height: 36px;
text-align: right;
font-family: "DejaVu Sans";
}
.estimate-details-container h4 {
margin: 0;
font-size: 10px;
line-height: 15px;
text-align: right;
}
.estimate-details-container h3 {
margin-bottom: 1px;
margin-top: 0;
}
/* -- Address -- */
.wrapper {
display: block;
margin-top: 60px;
padding-bottom: 20px;
}
.address {
.address-container {
display: block;
padding-top: 20px;
}
.company {
/* -- Company Address -- */
.company-address-container {
padding: 0 0 0 30px;
display: inline;
float:left;
width:30%;
float: left;
width: 30%;
}
.company h1 {
font-style: normal;
font-weight: bold;
.company-address-container {
padding-left: 30px;
float: left;
width: 30%;
text-transform: capitalize;
margin-bottom: 2px;
}
.company-address-container h1 {
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
margin-bottom: 0;
margin-bottom: 0px;
margin-top: 10px;
}
.company-add {
font-style: normal;
font-weight: normal;
font-size: 10px;
.company-address {
margin-top: 2px;
text-align: left;
font-size: 12px;
line-height: 15px;
color: #595959;
margin-top: 0px;
}
/* -------------------------- */
/* billing style */
.bill-address-container {
/* -- Billing -- */
.billing-address-container {
display: block;
/* position: absolute; */
float:right;
float: right;
padding: 0 40px 0 0;
}
.bill-to {
font-style: normal;
font-weight: normal;
.billing-address-label {
font-size: 12px;
line-height: 18px;
padding: 0px;
margin-bottom: 0px;
}
.bill-user-name {
max-width: 250px
font-style: normal;
font-weight: normal;
.billing-address-name {
max-width: 160px;
font-size: 15px;
line-height: 22px;
padding: 0px;
@ -134,9 +165,7 @@
margin-bottom: 0px;
}
.bill-user-address {
font-style: normal;
font-weight: normal;
.billing-address {
font-size: 10px;
line-height: 15px;
color: #595959;
@ -144,37 +173,24 @@
margin: 0px;
width: 170px;
}
.bill-user-phone {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
padding: 0px;
margin: 0px;
}
/* -------------------------- */
/* shipping style */
.ship-address-container {
/* -- Shipping -- */
.shipping-address-container {
display: block;
float:right;
float: right;
padding: 0 30px 0 0;
}
.ship-to {
font-style: normal;
font-weight: normal;
.shipping-address-label {
font-size: 12px;
line-height: 18px;
padding: 0px;
margin-bottom: 0px;
}
.ship-user-name {
max-width: 250px
font-style: normal;
font-weight: normal;
.shipping-address-name {
max-width: 160px;
font-size: 15px;
line-height: 22px;
padding: 0px;
@ -182,9 +198,7 @@
margin-bottom: 0px;
}
.ship-user-address {
font-style: normal;
font-weight: normal;
.shipping-address {
font-size: 10px;
line-height: 15px;
color: #595959;
@ -193,192 +207,114 @@
width: 170px;
}
.ship-user-phone {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
padding: 0px;
margin: 0px;
}
.job-add {
display: inline;
float: right;
width:40%;
}
.amount-due {
background-color: #f2f2f2;
}
.textRight {
text-align: right;
}
.textLeft {
text-align: left;
}
.textStyle1 {
.attribute-label {
font-size: 12;
font-weight: bold;
line-height:22px;
line-height: 22px;
color: rgba(0, 0, 0, 0.8);
}
.textStyle2 {
.attribute-value {
font-size: 12;
line-height:22px;
line-height: 22px;
color: rgba(0, 0, 0, 0.7);
}
.main-table-header td {
padding: 5px;
padding-bottom: 10px;
}
/* -- Items Table -- */
.main-table-header {
border-bottom: 1px solid red;
}
.table2 {
margin-top: 30px;
padding: 0px 30px 10px 30px;
.items-table {
padding: 30px 30px 10px 30px;
page-break-before: avoid;
page-break-after: auto;
}
hr {
margin: 0 30px 0 30px;
color:rgba(0, 0, 0, 0.2);
border: 0.5px solid #EAF1FB;
.items-table hr {
height: 0.1px;
margin: 0 30px;
}
.table2 hr {
height:0.1px;
}
.ItemTableHeader {
.item-table-heading {
font-size: 13.5;
text-align: center;
color: rgba(0, 0, 0, 0.85);
padding: 5px;
}
tr.main-table-header th {
.item-table-heading-row td {
padding: 5px;
padding-bottom: 10px;
}
.item-table-heading-row {
border-bottom: 1px solid red;
}
tr.item-table-heading-row th {
border-bottom: 0.620315px solid #E8E8E8;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
}
tr.item-details td {
font-style: normal;
font-weight: normal;
tr.item-row td {
font-size: 12px;
line-height: 18px;
}
.items {
.item-cell {
font-size: 13;
color: rgba(0, 0, 0, 0.6);
color: #040405;
text-align: center;
padding: 5px;
padding-top: 10px;
}
.note-header {
font-size: 13;
color: rgba(0, 0, 0, 0.6);
.item-description {
color: #595959;
font-size: 9px;
line-height: 12px;
page-break-inside: avoid;
}
.note-text {
font-size: 10;
color: rgba(0, 0, 0, 0.6);
/* -- Total Display Table -- */
.total-display-container {
padding: 0 25px;
}
.padd8 {
padding-top: 8px;
padding-bottom: 8px;
.item-cell-table-hr {
margin: 0 25px 0 30px;
}
.padd2 {
.total-display-table {
box-sizing: border-box;
page-break-inside: avoid;
page-break-before: auto;
page-break-after: auto;
margin-left: 500px;
border: 1px solid #EAF1FB;
border-top: none;
}
.total-table-attribute-label {
font-size: 12px;
color: #55547A;
text-align: left;
padding-left: 10px;
}
.total-table-attribute-value {
font-weight: bold;
text-align: right;
font-size: 12px;
color: #040405;
padding-right: 10px;
padding-top: 2px;
padding-bottom: 2px;
}
.table3 {
border: 1px solid #EAF1FB;
border-top: none;
box-sizing: border-box;
width: 630px;
page-break-inside: avoid;
page-break-before: auto;
page-break-after: auto;
}
.text-per-item-table3 {
border: 1px solid #EAF1FB;
border-top: none;
padding-right: 30px;
box-sizing: border-box;
width: 260px;
/* height: 100px; */
position: absolute;
right: -25;
}
.inv-item {
border-color: #d9d9d9;
}
.no-border {
border: none;
}
.desc {
font-weight: 100;
text-align: justify;
font-size: 10px;
margin-bottom: 15px;
margin-top:7px;
color:rgba(0, 0, 0, 0.85);
}
.company-details{
text-align: center;
width: 40%;
}
.company-details h1 {
margin:0;
font-style: normal;
font-weight: 500;
font-size: 24px;
line-height: 36px;
text-align: right;
}
.company-details h4 {
margin:0;
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
text-align: right;
}
.company-details h3 {
margin-bottom:1px;
margin-top:0;
}
/* -- Notes -- */
.notes {
font-style: normal;
font-weight: 300;
font-size: 12px;
color: #595959;
margin-top: 15px;
@ -389,8 +325,6 @@
}
.notes-label {
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
@ -400,23 +334,79 @@
padding-bottom: 10px;
}
/* -- Helpers -- */
.text-primary {
color: #5851DB;
}
.text-center {
text-align: center
}
table .text-left {
text-align: left;
}
table .text-right {
text-align: right;
}
.border-0 {
border: none;
}
.py-2 {
padding-top: 2px;
padding-bottom: 2px;
}
.py-8 {
padding-top: 8px;
padding-bottom: 8px;
}
.py-3 {
padding: 3px 0;
}
.pr-20 {
padding-right: 20px;
}
.pr-10 {
padding-right: 10px;
}
.pl-20 {
padding-left: 20px;
}
.pl-10 {
padding-left: 10px;
}
.pl-0 {
padding-left: 0;
}
</style>
</head>
<body>
<div class="header-table">
<div class="header-container">
<table width="100%">
<tr>
@if($logo)
<td width="60%" class="header-left">
<td width="60%" class="header-section-left">
<img class="header-logo" src="{{ $logo }}" alt="Company Logo">
@else
<td width="60%" class="header-left" style="padding-top: 0px;">
<td width="60%" class="header-section-left" style="padding-top: 0px;">
@if($estimate->user->company)
<h1 class="header-logo"> {{$estimate->user->company->name}} </h1>
@endif
@endif
</td>
<td width="40%" class="header-right company-details">
<td width="40%" class="header-section-right estimate-details-container">
<h1>Estimate</h1>
<h4>{{$estimate->estimate_number}}</h4>
<h4>{{$estimate->formattedEstimateDate}}</h4>
@ -426,24 +416,24 @@
</div>
<hr>
<div class="wrapper">
<div class="address">
<div class="company">
<div class="address-container">
<div class="company-address-container">
@include('app.pdf.estimate.partials.company-address')
</div>
<div class="ship-address-container">
<div class="shipping-address-container">
@include('app.pdf.estimate.partials.shipping-address')
</div>
@if($estimate->user->shippingaddress)
<div class="bill-address-container">
<div class="billing-address-container">
@else
<div class="bill-address-container" style="float:right;padding-right:0px;">
<div class="billing-address-container" style="float:right; padding-right:0px;">
@endif
@include('app.pdf.estimate.partials.billing-address')
</div>
<div style="clear: both;"></div>
</div>
@include('app.pdf.estimate.partials.table')
@include('app.pdf.estimate.partials.notes')
</div>
</body>
</html>

View File

@ -1,10 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>Estimate</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
/* -- Base -- */
body {
font-family: "DejaVu Sans";
}
@ -12,147 +14,138 @@
html {
margin: 0px;
padding: 0px;
margin-top: 50px;
}
table {
border-collapse: collapse;
}
.header-line {
color:rgba(0, 0, 0, 0.2);
position: absolute;
top: 80px;
left: 0px;
right: -70px;
width: 100%;
}
hr {
color:rgba(0, 0, 0, 0.2);
color: rgba(0, 0, 0, 0.2);
border: 0.5px solid #EAF1FB;
}
.items-table-hr{
margin: 0 30px 0 30px;
}
/* -- Header -- */
.header-left {
padding-top: 45px;
padding-bottom: 45px;
padding-left: 30px;
display:inline-block;
width:30%;
}
.header-table {
.header-container {
position: absolute;
width: 100%;
height: 150px;
left: 0px;
top: -60px;
}
.header-section-left {
padding-top: 45px;
padding-bottom: 45px;
padding-left: 30px;
display: inline-block;
width: 30%;
}
.header-bottom-divider {
color: rgba(0, 0, 0, 0.2);
position: absolute;
top: 100px;
left: 0px;
width: 100%;
}
.header-logo {
position: absolute;
height: 50px;
text-transform: capitalize;
color: #817AE3;
}
.header-right {
display:inline-block;
.header-section-right {
display: inline-block;
position: absolute;
right:0;
right: 0;
padding: 15px 30px 15px 0px;
float: right;
}
.inv-flex{
display:flex;
}
.inv-data{
text-align:right;
margin-right:120px;
}
.inv-value{
text-align:left;
margin-left:160px;
}
.header {
font-size: 20px;
color: rgba(0, 0, 0, 0.7);
}
.TextColor1 {
font-size: 16px;
color: rgba(0, 0, 0, 0.5);
/* -- Company Address -- */
.company-address-container {
width: auto;
text-transform: capitalize;
margin-bottom: 2px;
}
@page {
margin-top: 60px !important;
.company-address-container h1 {
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
margin-bottom: 0px;
margin-top: 10px;
}
.company-address {
margin-top: 2px;
text-align: left;
font-size: 12px;
line-height: 15px;
color: #595959;
}
/* -- Content Wrapper -- */
.wrapper {
display: block;
padding-top: 50px;
padding-top: 100px;
padding-bottom: 20px;
}
.address {
display: inline-block;
padding-top: 100px
.main-content {
}
.bill-add {
.customer-address-container {
display: inline;
float:left;
width:40%;
float: left;
width: 40%;
padding: 0 0 0 30px;
}
.company {
padding-left: 30px;
display: inline;
float:left;
width:30%;
/* -- Shipping -- */
.shipping-address-container {
float: right;
display: block;
}
.company h1 {
font-style: normal;
font-weight: bold;
font-size: 18px;
line-height: 22px;
letter-spacing: 0.05em;
.shipping-address-container--left {
float: left;
padding-left: 0;
}
.company-add {
text-align: left;
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
margin: 0px;
}
/* -------------------------- */
/* shipping style */
.ship-to {
.shipping-address-label {
padding-top: 5px;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
margin-bottom: 0px;
}
.ship-user-name {
.shipping-address-name {
padding: 0px;
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
margin: 0px;
max-width: 160px;
}
.ship-user-address {
font-style: normal;
font-weight: normal;
.shipping-address {
font-size: 10px;
line-height: 15px;
color: #595959;
@ -160,38 +153,28 @@
width: 160px;
}
.ship-user-phone {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
margin: 0px;
/* -- Billing -- */
.billing-address-container {
float: left;
}
/* -------------------------- */
/* billing style */
.bill-to {
.billing-address-label {
padding-top: 5px;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
margin-bottom: 0px;
}
.bill-user-name {
.billing-address-name {
padding: 0px;
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
margin: 0px;
max-width: 160px;
}
.bill-user-address {
font-style: normal;
font-weight: normal;
.billing-address {
font-size: 10px;
line-height: 15px;
color: #595959;
@ -199,187 +182,131 @@
width: 160px;
}
.bill-user-phone {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
margin: 0px;
}
/* -- Estimate Details -- */
.job-add {
.estimate-details-container {
display: block;
float: right;
padding: 20px 30px 0 0;
}
.amount-due {
background-color: #f2f2f2;
}
.textRight {
text-align: right;
}
.textLeft {
.attribute-label {
font-size: 12px;
line-height: 18px;
text-align: left;
color: #55547A
}
.textStyle1 {
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
}
.textStyle2 {
font-style: normal;
font-weight: normal;
.attribute-value {
font-size: 12px;
line-height: 18px;
text-align: right;
}
.main-table-header td {
padding: 10px;
}
.main-table-header {
border-bottom: 1px solid red;
}
tr.main-table-header th {
font-style: normal;
font-weight: 600;
font-size: 12px;
line-height: 18px;
}
tr.item-details td {
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
}
.table2 {
padding: 0px 30px 10px 30px;
/* -- Items Table -- */
.items-table {
padding: 30px 30px 10px 30px;
page-break-before: avoid;
page-break-after: auto;
}
.table2 hr {
height:0.1px;
.items-table hr {
height: 0.1px;
margin: 0 30px;
}
.ItemTableHeader {
.item-table-heading {
font-size: 13.5;
text-align: center;
color: rgba(0, 0, 0, 0.85);
padding: 5px;
padding-bottom: 10px;
}
.items {
tr.item-table-heading-row th {
border-bottom: 0.620315px solid #E8E8E8;
font-size: 12px;
line-height: 18px;
}
.item-table-heading-row {
margin-bottom: 10px;
}
tr.item-row td {
font-size: 12px;
line-height: 18px;
}
.item-cell {
font-size: 13;
color: rgba(0, 0, 0, 0.6);
color: #040405;
text-align: center;
padding: 5px;
padding-top: 10px;
border-color: #d9d9d9;
}
.note-header {
font-size: 13;
color: rgba(0, 0, 0, 0.6);
.item-description {
color: #595959;
font-size: 9px;
line-height: 12px;
}
.note-text {
font-size: 10;
color: rgba(0, 0, 0, 0.6);
.item-cell-table-hr {
margin: 0 30px 0 30px;
}
.padd8 {
padding-top: 8px;
padding-bottom: 8px;
/* -- Total Display Table -- */
.total-display-container {
padding: 0 25px;
}
.padd2 {
.total-display-table {
box-sizing: border-box;
page-break-inside: avoid;
page-break-before: auto;
page-break-after: auto;
margin-left: 500px;
margin-top: 20px;
}
.total-table-attribute-label {
font-size: 12px;
color: #55547A;
text-align: left;
padding-left: 10px;
}
.total-table-attribute-value {
font-weight: bold;
text-align: right;
font-size: 12px;
color: #040405;
padding-right: 10px;
padding-top: 2px;
padding-bottom: 2px;
}
.table3 {
border: 1px solid #EAF1FB;
border-top: none;
box-sizing: border-box;
width: 630px;
page-break-inside: avoid;
page-break-before: auto;
page-break-after: auto;
.total-border-left {
border: 1px solid #E8E8E8 !important;
border-right: 0px !important;
padding-top: 0px;
padding: 8px !important;
}
td.estimate-total1 {
text-align:left;
padding: 15px 0 15px 10px;
font-size:12px;
line-height: 18px;
color: #55547A;
border-bottom:1px solid #E8E8E8;
border-top:1px solid #E8E8E8;
border-left:1px solid #E8E8E8;
.total-border-right {
border: 1px solid #E8E8E8 !important;
border-left: 0px !important;
padding-top: 0px;
padding: 8px !important;
}
td.estimate-total2 {
font-weight: 500;
text-align: right;
font-size:12px;
line-height: 18px;
padding: 15px 10px 15px 0;
color: #5851DB;
border-bottom:1px solid #E8E8E8;
border-top:1px solid #E8E8E8;
border-right:1px solid #E8E8E8;
}
.inv-item {
border-color: #d9d9d9;
}
.no-border {
border: none;
}
.desc {
font-weight: 100;
text-align: justify;
font-size: 10px;
margin-bottom: 15px;
margin-top:7px;
color:rgba(0, 0, 0, 0.85);
}
.company-details h1 {
margin:0;
font-style: normal;
font-weight: bold;
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
text-align: left;
max-width: 220px;
}
.company-details h4 {
margin:0;
font-style: normal;
font-weight: 100;
font-size: 18px;
line-height: 25px;
text-align: right;
}
.company-details h3 {
margin-bottom:1px;
margin-top:0;
}
tr.total td {
border-bottom:1px solid #E8E8E8;
border-top:1px solid #E8E8E8;
}
/* -- Notes -- */
.notes {
font-style: normal;
font-weight: 300;
font-size: 12px;
color: #595959;
margin-top: 15px;
@ -390,8 +317,6 @@
}
.notes-label {
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
@ -401,60 +326,116 @@
padding-bottom: 10px;
}
/* -- Helpers -- */
.text-primary {
color: #5851DB;
}
.text-center {
text-align: center
}
table .text-left {
text-align: left;
}
table .text-right {
text-align: right;
}
.border-0 {
border: none;
}
.py-2 {
padding-top: 2px;
padding-bottom: 2px;
}
.py-8 {
padding-top: 8px;
padding-bottom: 8px;
}
.py-3 {
padding: 3px 0;
}
.pr-20 {
padding-right: 20px;
}
.pr-10 {
padding-right: 10px;
}
.pl-20 {
padding-left: 20px;
}
.pl-10 {
padding-left: 10px;
}
.pl-0 {
padding-left: 0;
}
</style>
</head>
<body>
<div class="header-table">
<div class="header-container">
<table width="100%">
<tr>
@if($logo)
<td class="header-left">
<td class="header-section-left">
<img class="header-logo" src="{{ $logo }}" alt="Company Logo">
@else
@if($estimate->user->company)
<td class="header-left" style="padding-top:0px;">
<td class="header-section-left" style="padding-top:0px;">
<h1 class="header-logo"> {{$estimate->user->company->name}} </h1>
@endif
@endif
</td>
<td class="header-right company-details">
<td class="header-section-right company-address-container">
@include('app.pdf.estimate.partials.company-address')
</td>
</tr>
</table>
</div>
<hr class="header-line">
<hr class="header-bottom-divider">
<div class="wrapper">
<div class="address">
<div class="bill-add">
<div style="float:left;">
<div class="main-content">
<div class="customer-address-container">
<div class="billing-address-container">
@include('app.pdf.estimate.partials.billing-address')
</div>
@if($estimate->user->billingaddress)
<div style="float:right;">
<div class="shipping-address-container">
@else
<div style="float:left;">
<div class="shipping-address-container--left">
@endif
@include('app.pdf.estimate.partials.shipping-address')
</div>
<div style="clear: both;"></div>
</div>
<div class="job-add">
<div class="estimate-details-container">
<table>
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Estimate Number</td>
<td class="textStyle2"> &nbsp;{{$estimate->estimate_number}}</td>
<td class="attribute-label">Estimate Number</td>
<td class="attribute-value"> &nbsp;{{$estimate->estimate_number}}</td>
</tr>
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Estimate Date </td>
<td class="textStyle2"> &nbsp;{{$estimate->formattedEstimateDate}}</td>
<td class="attribute-label">Estimate Date </td>
<td class="attribute-value"> &nbsp;{{$estimate->formattedEstimateDate}}</td>
</tr>
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Expiry Date</td>
<td class="textStyle2"> &nbsp;{{$estimate->formattedExpiryDate}}</td>
<td class="attribute-label">Expiry Date</td>
<td class="attribute-value"> &nbsp;{{$estimate->formattedExpiryDate}}</td>
</tr>
</table>
</div>
@ -463,5 +444,7 @@
@include('app.pdf.estimate.partials.table')
@include('app.pdf.estimate.partials.notes')
</div>
</div>
</body>
</html>

View File

@ -1,11 +1,11 @@
@if($estimate->user->billingaddress)
<p class="bill-to">Bill To,</p>
<p class="billing-address-label">Bill To,</p>
@if($estimate->user->billingaddress->name)
<p class="bill-user-name">
<p class="billing-address-name">
{{$estimate->user->billingaddress->name}}
</p>
@endif
<p class="bill-user-address">
<p class="billing-address">
@if($estimate->user->billingaddress->address_street_1)
{!! nl2br(htmlspecialchars($estimate->user->billingaddress->address_street_1)) !!}<br>
@endif
@ -31,7 +31,7 @@
@endif
@if($estimate->user->billingaddress->phone)
<p class="bill-user-phone">
<p class="billing-address">
Phone :{{$estimate->user->billingaddress->phone}}
</p>
@endif

View File

@ -3,7 +3,7 @@
@endif
@if($company_address)
<p class="company-add">
<p class="company-address">
@if($company_address->addresses[0]['address_street_1'])
{!! nl2br(htmlspecialchars($company_address->addresses[0]['address_street_1'])) !!} <br>
@endif

View File

@ -1,11 +1,11 @@
@if($estimate->user->shippingaddress)
<p class="ship-to">Ship To,</p>
<p class="shipping-address-label">Ship To,</p>
@if($estimate->user->shippingaddress->name)
<p class="ship-user-name">
<p class="shipping-address-name">
{{$estimate->user->shippingaddress->name}}
</p>
@endif
<p class="ship-user-address">
<p class="shipping-address">
@if($estimate->user->shippingaddress->address_street_1)
{!! nl2br(htmlspecialchars($estimate->user->shippingaddress->address_street_1)) !!}<br>
@endif
@ -30,8 +30,8 @@
{{$estimate->user->shippingaddress->country->name}}<br>
@endif
@if($estimate->user->phone)
<p class="ship-user-phone">
@if($estimate->user->shippingAddress->phone)
<p class="shipping-address">
Phone :{{$estimate->user->shippingaddress->phone}}
</p>
@endif

View File

@ -1,50 +1,49 @@
<table width="100%" class="table2" cellspacing="0" border="0">
<tr class="main-table-header">
<th width="2%" class="ItemTableHeader" style="text-align: right; color: #55547A; padding-right: 20px">#</th>
<th width="40%" class="ItemTableHeader" style="text-align: left; color: #55547A; padding-left: 0px">Items</th>
<th class="ItemTableHeader" style="text-align: right; color: #55547A; padding-right: 20px">Quantity</th>
<th class="ItemTableHeader" style="text-align: right; color: #55547A; padding-right: 20px">Price</th>
<table width="100%" class="items-table" cellspacing="0" border="0">
<tr class="item-table-heading-row">
<th width="2%" class="item-table-heading text-right pr-20">#</th>
<th width="40%" class="item-table-heading text-left pl-0">Items</th>
<th class="item-table-heading text-right pr-20">Quantity</th>
<th class="item-table-heading text-right pr-20">Price</th>
@if($estimate->discount_per_item === 'YES')
<th class="ItemTableHeader" style="text-align: right; color: #55547A; padding-left: 10px">Discount</th>
<th class="item-table-heading text-right pl-10">Discount</th>
@endif
<th class="ItemTableHeader" style="text-align: right; color: #55547A;">Amount</th>
<th class="item-table-heading text-right">Amount </th>
</tr>
@php
$index = 1
@endphp
@foreach ($estimate->items as $item)
<tr class="item-details">
<tr class="item-row">
<td
class="inv-item items"
style="text-align: right; color: #040405; padding-right: 20px; vertical-align: top;"
class="item-cell text-right pr-20"
style="vertical-align: top;"
>
{{$index}}
</td>
<td
class="inv-item items"
style="text-align: left; color: #040405;padding-left: 0px"
class="item-cell text-left pl-0"
>
<span>{{ $item->name }}</span><br>
<span
style="text-align: left; color: #595959; font-size: 9px; font-weight:300; line-height: 12px;"
class="item-description"
>
{!! nl2br(htmlspecialchars($item->description)) !!}
</span>
</td>
<td
class="inv-item items"
style="text-align: right; color: #040405; padding-right: 20px"
class="item-cell text-right pr-20"
style="vertical-align: top;"
>
{{$item->quantity}}
</td>
<td
class="inv-item items"
style="text-align: right; color: #040405; padding-right: 20px"
class="item-cell text-right pr-20"
style="vertical-align: top;"
>
{!! format_money_pdf($item->price, $estimate->user->currency) !!}
</td>
@if($estimate->discount_per_item === 'YES')
<td class="inv-item items" style="text-align: right; color: #040405; padding-left: 10px">
<td class="item-cell text-right pl-10" style="vertical-align: top;">
@if($item->discount_type === 'fixed')
{!! format_money_pdf($item->discount_val, $estimate->user->currency) !!}
@endif
@ -53,7 +52,7 @@
@endif
</td>
@endif
<td class="inv-item items" style="text-align: right; color: #040405;">
<td class="item-cell text-right" style="vertical-align: top;">
{!! format_money_pdf($item->total, $estimate->user->currency) !!}
</td>
</tr>
@ -63,22 +62,22 @@
@endforeach
</table>
<hr class="items-table-hr">
<hr class="item-cell-table-hr">
<table width="100%" cellspacing="0px" style="margin-left:420px;margin-top: 10px" border="0" class="table3 @if(count($estimate->items) > 12) page-break @endif">
<div class="total-display-container">
<table width="100%" cellspacing="0px" border="0" class="total-display-table @if(count($estimate->items) > 12) page-break @endif">
<tr>
<td class="no-borde" style="color: #55547A; padding-left:10px; font-size:12px;">Subtotal</td>
<td class="no-border items"
style="padding-right:10px; text-align: right; font-size:12px; color: #040405; font-weight: 500;">{!! format_money_pdf($estimate->sub_total, $estimate->user->currency) !!}</td>
<td class="border-0 total-table-attribute-label">Subtotal</td>
<td class="border-0 item-cell total-table-attribute-value ">{!! format_money_pdf($estimate->sub_total, $estimate->user->currency) !!}</td>
</tr>
@if ($estimate->tax_per_item === 'YES')
@for ($i = 0; $i < count($labels); $i++)
<tr>
<td class="no-border" style="padding-left:10px; text-align:left; font-size:12px; color: #55547A;">
<td class="border-0 total-table-attribute-label">
{{$labels[$i]}}
</td>
<td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px; color: #040405">
<td class="border-0 item-cell total-table-attribute-value">
{!! format_money_pdf($taxes[$i], $estimate->user->currency) !!}
</td>
</tr>
@ -86,10 +85,10 @@
@else
@foreach ($estimate->taxes as $tax)
<tr>
<td class="no-border" style="padding-left:10px; text-align:left; font-size:12px; color: #55547A;">
<td class="border-0 total-table-attribute-label">
{{$tax->name.' ('.$tax->percent.'%)'}}
</td>
<td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px; color: #040405">
<td class="border-0 item-cell total-table-attribute-value" >
{!! format_money_pdf($tax->amount, $estimate->user->currency) !!}
</td>
</tr>
@ -98,7 +97,7 @@
@if ($estimate->discount_per_item === 'NO')
<tr>
<td class="no-border" style="padding-left:10px; text-align:left; font-size:12px; color: #55547A;">
<td class="border-0 total-table-attribute-label pl-10">
@if($estimate->discount_type === 'fixed')
Discount
@endif
@ -106,7 +105,7 @@
Discount ({{$estimate->discount}}%)
@endif
</td>
<td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px; color: #040405">
<td class="border-0 item-cell total-table-attribute-value text-right">
@if($estimate->discount_type === 'fixed')
{!! format_money_pdf($estimate->discount_val, $estimate->user->currency) !!}
@endif
@ -117,20 +116,14 @@
</tr>
@endif
<tr>
<td style="padding:3px 0px"></td>
<td style="padding:3px 0px"></td>
<td class="py-3"></td>
<td class="py-3"></td>
</tr>
<tr>
<td class="no-border total-border-left"
style="padding-left:10px; padding-bottom:10px; text-align:left; padding-top:20px; font-size:12px; color: #55547A;"
>
<label class="total-bottom"> Total </label>
</td>
<td
class="no-border total-border-right items padd8"
style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px; padding-top:20px; color: #5851DB"
>
<td class="border-0 total-border-left total-table-attribute-label">Total</td>
<td class="border-0 total-border-right item-cell py-8 total-table-attribute-value text-primary">
{!! format_money_pdf($estimate->total, $estimate->user->currency)!!}
</td>
</tr>
</table>
</table>
</div>

View File

@ -1,10 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>Invoice</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
/* -- Base -- */
body {
font-family: "DejaVu Sans";
}
@ -15,29 +17,27 @@
margin-top: 50px;
}
table {
border-collapse: collapse;
.text-center {
text-align: center
}
.header-line {
color:rgba(0, 0, 0, 0.2);
hr {
margin: 0 30px 0 30px;
color: rgba(0, 0, 0, 0.2);
border: 0.5px solid #EAF1FB;
}
/* -- Header -- */
.header-bottom-divider {
color: rgba(0, 0, 0, 0.2);
position: absolute;
top: 90px;
left: 0px;
width: 100%;
}
hr {
margin: 0 30px 0 30px;
color:rgba(0, 0, 0, 0.2);
border: 0.5px solid #EAF1FB;
}
.header-center {
text-align: center
}
.header-table {
.header-container {
position: absolute;
width: 100%;
height: 90px;
@ -52,122 +52,69 @@
color: #817AE3;
}
.inv-flex{
display:flex;
}
.inv-data{
text-align:right;
margin-right:120px;
}
.inv-value{
text-align:left;
margin-left:160px;
}
.header {
font-size: 20px;
color: rgba(0, 0, 0, 0.7);
}
.TextColor1 {
font-size: 16px;
color: rgba(0, 0, 0, 0.5);
}
@page {
margin-top: 60px !important;
}
.wrapper {
.content-wrapper {
display: block;
margin-top: 0px;
padding-top: 16px;
padding-bottom: 20px;
}
.address {
/* display: inline-block; */
padding-top: 30px
}
.company {
float: left;
.company-address-container {
padding-left: 30px;
font-weight: normal;
display: inline;
float:left;
width:30%;
float: left;
width: 30%;
text-transform: capitalize;
margin-bottom: 2px;
}
.company h1 {
font-style: normal;
font-weight: normal;
.company-address-container h1 {
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
margin-bottom: 0px;
margin-top: 10px;
}
.company-add {
.company-address {
margin-top: 2px;
text-align: left;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 15px;
color: #595959;
}
.job-add {
/* display: inline; */
.invoice-details-container {
float: right;
padding: 10px 30px 0 0;
}
.amount-due {
background-color: #f2f2f2;
}
.textRight {
text-align: right;
}
.textLeft {
text-align: left;
}
.textStyle1 {
font-style: normal;
font-weight: normal;
.attribute-label {
font-size: 12px;
line-height: 18px;
padding-right: 40px;
text-align: left;
color: #55547A;
}
.textStyle2 {
font-style: normal;
font-weight: normal;
.attribute-value {
font-size: 12px;
line-height: 18px;
text-align: right;
}
.bill-add {
width:45%;
padding: 0px 0 0 0px;
}
/* -------------------------- */
/* shipping style */
/* -- Shipping -- */
.ship-address-container {
.shipping-address-container {
float: right;
padding-left: 30px;
}
.ship-to {
font-style: normal;
font-weight: normal;
.shipping-address-label {
font-size: 12px;
line-height: 18px;
padding: 0px;
@ -175,18 +122,15 @@
margin-bottom: 0px;
}
.ship-user-name {
max-width: 250px
font-style: normal;
font-weight: normal;
.shipping-address-name {
max-width: 160px;
font-size: 15px;
line-height: 22px;
padding: 0px;
margin: 0px;
}
.ship-user-address {
font-style: normal;
font-weight: normal;
.shipping-address {
font-size: 10px;
line-height: 15px;
color: #595959;
@ -194,27 +138,15 @@
margin: 0px;
width: 160px;
}
.ship-user-phone {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
padding: 0px;
margin: 0px;
}
/* -------------------------- */
/* billing style */
/* -- Billing -- */
.bill-address-container {
.billing-address-container {
float: left;
padding-left: 30px;
}
.bill-to {
font-style: normal;
font-weight: normal;
.billing-address-label {
font-size: 12px;
line-height: 18px;
padding: 0px;
@ -222,19 +154,15 @@
margin-bottom: 0px;
}
.bill-user-name {
max-width: 250px
font-style: normal;
font-weight: normal;
.billing-address-name {
max-width: 160px;
font-size: 15px;
line-height: 22px;
padding: 0px;
margin: 0px;
}
.bill-user-address {
font-style: normal;
font-weight: normal;
.billing-address {
font-size: 10px;
line-height: 15px;
color: #595959;
@ -243,115 +171,102 @@
width: 160px;
}
.bill-user-phone {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
padding: 0px;
margin: 0px;
}
/* -- Items Table -- */
.table2 {
.items-table {
margin-top: 35px;
padding: 0px 30px 10px 30px;
page-break-before: avoid;
page-break-after: auto;
}
.table2 hr {
height:0.1px;
.items-table hr {
height: 0.1px;
}
.ItemTableHeader {
.item-table-heading {
font-size: 13.5;
text-align: center;
color: rgba(0, 0, 0, 0.85);
padding: 5px;
color: #55547A;
}
tr.main-table-header th {
tr.item-table-heading-row th {
border-bottom: 0.620315px solid #E8E8E8;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
}
tr.item-details td {
font-style: normal;
font-weight: normal;
tr.item-row td {
font-size: 12px;
line-height: 18px;
}
.items {
.item-cell {
font-size: 13;
color: rgba(0, 0, 0, 0.6);
text-align: center;
padding: 5px;
padding-top: 10px;
color: #040405;
}
.padd8 {
padding-top: 8px;
padding-bottom: 8px;
.item-description {
color: #595959;
font-size: 9px;
line-height: 12px;
}
.padd2 {
/* -- Total Display Table -- */
.total-display-container {
padding: 0 25px;
}
.total-display-table {
border-top: none;
box-sizing: border-box;
page-break-inside: avoid;
page-break-before: auto;
page-break-after: auto;
margin-left: 500px;
margin-top: 20px;
}
.total-table-attribute-label {
font-size: 13px;
color: #55547A;
text-align: left;
padding-left: 10px;
}
.total-table-attribute-value {
font-weight: bold;
text-align: right;
font-size: 13px;
color: #040405;
padding-right: 10px;
padding-top: 2px;
padding-bottom: 2px;
}
.table3 {
/* border: 1px solid #EAF1FB; */
border-top: none;
/* padding-right: 30px; */
box-sizing: border-box;
width: 630px;
/* position: absolute;
right: -25; */
page-break-inside: avoid;
page-break-before: auto;
page-break-after: auto;
}
.total-border-left {
border: 1px solid #E8E8E8!important;
border: 1px solid #E8E8E8 !important;
border-right: 0px !important;
padding-top: 0px;
padding:8px !important;
padding: 8px !important;
}
.total-border-right {
border: 1px solid #E8E8E8!important;
border: 1px solid #E8E8E8 !important;
border-left: 0px !important;
padding-top: 0px;
padding:8px !important;
padding: 8px !important;
}
.inv-item {
border-color: #d9d9d9;
}
.no-border {
border: none;
}
.desc {
font-weight: 100;
text-align: justify;
font-size: 10px;
margin-bottom: 15px;
margin-top:7px;
color:rgba(0, 0, 0, 0.85);
}
/* -- Notes -- */
.notes {
font-style: normal;
font-weight: 300;
font-size: 12px;
color: #595959;
margin-top: 15px;
@ -362,8 +277,6 @@
}
.notes-label {
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
@ -373,13 +286,69 @@
padding-bottom: 10px;
}
/* -- Helpers -- */
.text-primary {
color: #5851DB;
}
.text-center {
text-align: center
}
table .text-left {
text-align: left;
}
table .text-right {
text-align: right;
}
.border-0 {
border: none;
}
.py-2 {
padding-top: 2px;
padding-bottom: 2px;
}
.py-8 {
padding-top: 8px;
padding-bottom: 8px;
}
.py-3 {
padding: 3px 0;
}
.pr-20 {
padding-right: 20px;
}
.pr-10 {
padding-right: 10px;
}
.pl-20 {
padding-left: 20px;
}
.pl-10 {
padding-left: 10px;
}
.pl-0 {
padding-left: 0;
}
</style>
</head>
<body>
<div class="header-table">
<div class="header-container">
<table width="100%">
<tr>
<td class="header-center">
<td class="text-center">
@if($logo)
<img class="header-logo" src="{{ $logo }}" alt="Company Logo">
@else
@ -390,48 +359,44 @@
</td>
</tr>
</table>
<hr class="header-line" style="border: 0.620315px solid #E8E8E8;"/>
<hr class="header-bottom-divider" style="border: 0.620315px solid #E8E8E8;" />
</div>
<div class="wrapper">
<div class="address">
<div class="company">
<div class="content-wrapper">
<div style="padding-top: 30px">
<div class="company-address-container">
@include('app.pdf.invoice.partials.company-address')
</div>
<div class="job-add">
<div class="invoice-details-container">
<table>
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Invoice Number</td>
<td class="textStyle2"> &nbsp;{{$invoice->invoice_number}}</td>
<td class="attribute-label">Invoice Number</td>
<td class="attribute-value"> &nbsp;{{$invoice->invoice_number}}</td>
</tr>
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Invoice Date </td>
<td class="textStyle2"> &nbsp;{{$invoice->formattedInvoiceDate}}</td>
<td class="attribute-label">Invoice Date </td>
<td class="attribute-value"> &nbsp;{{$invoice->formattedInvoiceDate}}</td>
</tr>
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Due date</td>
<td class="textStyle2"> &nbsp;{{$invoice->formattedDueDate}}</td>
<td class="attribute-label">Due date</td>
<td class="attribute-value"> &nbsp;{{$invoice->formattedDueDate}}</td>
</tr>
</table>
</div>
<div style="clear: both;"></div>
</div>
<div class="bill-add">
<div class="bill-address-container">
<div class="billing-address-container">
@include('app.pdf.invoice.partials.billing-address')
</div>
@if($invoice->user->billingaddress)
<div class="ship-address-container">
@else
<div class="ship-address-container " style="float:left;padding-left:0px;">
@endif
<div class="shipping-address-container" @if($invoice->user->billingaddress) style="float:left;" @else style="float:left: padding-left: 0px;" @endif>
@include('app.pdf.invoice.partials.shipping-address')
@if($invoice->user->billingaddress) <div style="clear: both;"></div> @endif
</div>
<div style="clear: both;"></div>
</div>
<div style="position:relative">
<div style="position: relative; clear: both;">
@include('app.pdf.invoice.partials.table')
</div>
@include('app.pdf.invoice.partials.notes')
</div>
</body>
</html>

View File

@ -1,10 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>Invoice</title>
{{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}}
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
/* -- Base -- */
body {
font-family: "DejaVu Sans";
}
@ -12,22 +13,22 @@
html {
margin: 0px;
padding: 0px;
margin-top: 50px;
}
table {
border-collapse: collapse;
}
.header-left {
padding-top: 45px;
padding-bottom: 45px;
padding-left: 30px;
display:inline-block;
width:30%;
hr {
margin: 0 30px 0 30px;
color: rgba(0, 0, 0, 0.2);
border: 0.5px solid #EAF1FB;
}
@page {
margin-top: 60px !important;
}
.header-table {
/* -- Header -- */
.header-container {
background: #817AE3;
position: absolute;
width: 100%;
@ -35,351 +36,266 @@
left: 0px;
top: -60px;
}
.header-section-left {
padding-top: 45px;
padding-bottom: 45px;
padding-left: 30px;
display: inline-block;
width: 30%;
}
.header-logo {
position: absolute;
height: 50px;
text-transform: capitalize;
color: #fff;
}
.header-right {
display:inline-block;
width:35%;
float:right;
.header-section-right {
display: inline-block;
width: 35%;
float: right;
padding: 20px 30px 20px 0px;
text-align: right;
color:white;
color: white;
}
}
.inv-flex{
display:flex;
}
.inv-data{
text-align:right;
margin-right:120px;
}
.inv-value{
text-align:left;
margin-left:160px;
}
.header {
font-size: 20px;
color: rgba(0, 0, 0, 0.7);
}
.TextColor1 {
font-size: 16px;
color: rgba(0, 0, 0, 0.5);
}
/* -- Estimate Details -- */
.wrapper {
display: block;
margin-top: 60px;
padding-bottom: 20px;
}
.address {
display: block;
padding-top: 20px;
}
.company {
padding: 0 0 0 30px;
display: inline;
float:left;
width:30%;
}
.company h1 {
font-style: normal;
font-weight: bold;
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
margin-bottom: 0;
}
.company-add {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
margin-top: 0px;
}
/* -------------------------- */
/* billing style */
.bill-address-container {
display: block;
/* position: absolute; */
float:right;
padding: 0 40px 0 0;
}
.bill-to {
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
padding: 0px;
margin-bottom: 0px;
}
.bill-user-name {
max-width: 250px
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
padding: 0px;
margin-top: 0px;
margin-bottom: 0px;
}
.bill-user-address {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
padding: 0px;
margin: 0px;
width: 170px;
}
.bill-user-phone {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
padding: 0px;
margin: 0px;
}
/* -------------------------- */
/* shipping style */
.ship-address-container {
display: block;
float:right;
padding: 0 30px 0 0;
}
.ship-to {
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
padding: 0px;
margin-bottom: 0px;
}
.ship-user-name {
max-width: 250px
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
padding: 0px;
margin-top: 0px;
margin-bottom: 0px;
}
.ship-user-address {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
padding: 0px;
margin: 0px;
width: 170px;
}
.ship-user-phone {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
padding: 0px;
margin: 0px;
}
.job-add {
display: inline;
float: right;
width:40%;
}
.amount-due {
background-color: #f2f2f2;
}
.textRight {
text-align: right;
}
.textLeft {
text-align: left;
}
.textStyle1 {
font-size: 12;
font-weight: bold;
line-height:22px;
color: rgba(0, 0, 0, 0.8);
}
.textStyle2 {
font-size: 12;
line-height:22px;
color: rgba(0, 0, 0, 0.7);
}
.main-table-header td {
padding: 5px;
padding-bottom: 10px;
}
.main-table-header {
border-bottom: 1px solid red;
}
.table2 {
margin-top: 30px;
padding: 0px 30px 10px 30px;
page-break-before: avoid;
page-break-after: auto;
}
hr {
margin: 0 30px 0 30px;
color:rgba(0, 0, 0, 0.2);
border: 0.5px solid #EAF1FB;
}
.table2 hr {
height:0.1px;
}
.ItemTableHeader {
font-size: 13.5;
text-align: center;
color: rgba(0, 0, 0, 0.85);
padding: 5px;
}
tr.main-table-header th {
border-bottom: 0.620315px solid #E8E8E8;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
}
tr.item-details td {
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
}
.items {
font-size: 13;
color: rgba(0, 0, 0, 0.6);
text-align: center;
padding: 5px;
padding-top: 10px;
}
.note-header {
font-size: 13;
color: rgba(0, 0, 0, 0.6);
}
.note-text {
font-size: 10;
color: rgba(0, 0, 0, 0.6);
}
.padd8 {
padding-top: 8px;
padding-bottom: 8px;
}
.padd2 {
padding-top: 2px;
padding-bottom: 2px;
}
.table3 {
border: 1px solid #EAF1FB;
border-top: none;
box-sizing: border-box;
width: 630px;
page-break-inside: avoid;
page-break-before: auto;
page-break-after: auto;
}
.text-per-item-table3 {
border: 1px solid #EAF1FB;
border-top: none;
padding-right: 30px;
box-sizing: border-box;
width: 260px;
/* height: 100px; */
position: absolute;
right: -25;
}
.inv-item {
border-color: #d9d9d9;
}
.no-border {
border: none;
}
.desc {
font-weight: 100;
text-align: justify;
font-size: 10px;
margin-bottom: 15px;
margin-top:7px;
color:rgba(0, 0, 0, 0.85);
}
.company-details{
.invoice-details-container {
text-align: center;
width: 40%;
}
.company-details h1 {
margin:0;
font-style: normal;
font-weight: 500;
.invoice-details-container h1 {
margin: 0;
font-size: 24px;
line-height: 36px;
text-align: right;
}
.company-details h4 {
margin:0;
font-style: normal;
font-weight: normal;
.invoice-details-container h4 {
margin: 0;
font-size: 10px;
line-height: 15px;
text-align: right;
}
.company-details h3 {
margin-bottom:1px;
margin-top:0;
.invoice-details-container h3 {
margin-bottom: 1px;
margin-top: 0;
}
/* -- Content Wrapper -- */
.content-wrapper {
display: block;
margin-top: 60px;
padding-bottom: 20px;
}
.address-container {
display: block;
padding-top: 20px;
}
/* -- Company -- */
.company-address-container {
padding: 0 0 0 30px;
display: inline;
float: left;
width: 30%;
}
.company-address-container h1 {
font-weight: bold;
font-size: 15px;
letter-spacing: 0.05em;
margin-bottom: 0;
margin-top: 18px;
}
.company-address{
font-size: 10px;
line-height: 15px;
color: #595959;
margin-top: 0px;
}
/* -- Billing -- */
.billing-address-container {
display: block;
/* position: absolute; */
float: right;
padding: 0 40px 0 0;
}
.billing-address-label {
font-size: 12px;
line-height: 18px;
padding: 0px;
margin-bottom: 0px;
}
.billing-address-name {
max-width: 250px;
font-size: 15px;
line-height: 22px;
padding: 0px;
margin-top: 0px;
margin-bottom: 0px;
}
.billing-address{
font-size: 10px;
line-height: 15px;
color: #595959;
padding: 0px;
margin: 0px;
width: 170px;
}
/* -- Shipping -- */
.shipping-address-container {
display: block;
float: right;
padding: 0 30px 0 0;
}
.shipping-address-label {
font-size: 12px;
line-height: 18px;
padding: 0px;
margin-bottom: 0px;
}
.shipping-address-name {
max-width: 250px;
font-size: 15px;
line-height: 22px;
padding: 0px;
margin-top: 0px;
margin-bottom: 0px;
}
.shipping-address {
font-size: 10px;
line-height: 15px;
color: #595959;
padding: 0px;
margin: 0px;
width: 170px;
}
/* -- Items Table -- */
.items-table {
margin-top: 35px;
padding: 0px 30px 10px 30px;
page-break-before: avoid;
page-break-after: auto;
}
.items-table hr {
height: 0.1px;
}
.item-table-heading {
font-size: 13.5;
text-align: center;
color: rgba(0, 0, 0, 0.85);
padding: 5px;
color: #55547A;
}
tr.item-table-heading-row th {
border-bottom: 0.620315px solid #E8E8E8;
font-size: 12px;
line-height: 18px;
}
tr.item-row td {
font-size: 12px;
line-height: 18px;
}
.item-cell {
font-size: 13;
text-align: center;
padding: 5px;
padding-top: 10px;
color: #040405;
}
.item-description {
color: #595959;
font-size: 9px;
line-height: 12px;
}
/* -- Total Display Table -- */
.total-display-container {
padding: 0 25px;
}
.item-cell-table-hr {
margin: 0 25px 0 30px;
}
.total-display-table {
box-sizing: border-box;
page-break-inside: avoid;
page-break-before: auto;
page-break-after: auto;
margin-left: 500px;
border: 1px solid #EAF1FB;
border-top: none;
}
.total-table-attribute-label {
font-size: 12px;
color: #55547A;
text-align: left;
padding-left: 10px;
}
.total-table-attribute-value {
font-weight: 500;
text-align: right;
font-size: 12px;
color: #040405;
padding-right: 10px;
padding-top: 2px;
padding-bottom: 2px;
}
.total-border-left {
border: 1px solid #E8E8E8 !important;
border-right: 0px !important;
padding-top: 0px;
padding: 8px !important;
}
.total-border-right {
border: 1px solid #E8E8E8 !important;
border-left: 0px !important;
padding-top: 0px;
padding: 8px !important;
}
/* -- Notes -- */
.notes {
font-style: normal;
font-weight: 300;
font-size: 12px;
color: #595959;
margin-top: 15px;
@ -390,8 +306,6 @@
}
.notes-label {
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
@ -401,23 +315,79 @@
padding-bottom: 10px;
}
/* -- Helpers -- */
.text-primary {
color: #5851DB;
}
.text-center {
text-align: center
}
table .text-left {
text-align: left;
}
table .text-right {
text-align: right;
}
.border-0 {
border: none;
}
.py-2 {
padding-top: 2px;
padding-bottom: 2px;
}
.py-8 {
padding-top: 8px;
padding-bottom: 8px;
}
.py-3 {
padding: 3px 0;
}
.pr-20 {
padding-right: 20px;
}
.pr-10 {
padding-right: 10px;
}
.pl-20 {
padding-left: 20px;
}
.pl-10 {
padding-left: 10px;
}
.pl-0 {
padding-left: 0;
}
</style>
</head>
<body>
<div class="header-table">
<div class="header-container">
<table width="100%">
<tr>
@if($logo)
<td width="60%" class="header-left">
<td width="60%" class="header-section-left">
<img class="header-logo" src="{{ $logo }}" alt="Company Logo">
@else
<td width="60%" class="header-left" style="padding-top: 0px;">
<td width="60%" class="header-section-left" style="padding-top: 0px;">
@if($invoice->user->company)
<h1 class="header-logo"> {{$invoice->user->company->name}} </h1>
@endif
@endif
</td>
<td width="40%" class="header-right company-details">
<td width="40%" class="header-section-right invoice-details-container">
<h1>Invoice</h1>
<h4>{{$invoice->invoice_number}}</h4>
<h4>{{$invoice->formattedInvoiceDate}}</h4>
@ -426,18 +396,18 @@
</table>
</div>
<hr>
<div class="wrapper">
<div class="address">
<div class="company">
<div class="content-wrapper">
<div class="address-container">
<div class="company-address-container">
@include('app.pdf.invoice.partials.company-address')
</div>
<div class="ship-address-container">
<div class="shipping-address-container">
@include('app.pdf.invoice.partials.shipping-address')
</div>
@if($invoice->user->shippingaddress)
<div class="bill-address-container">
<div class="billing-address-container">
@else
<div class="bill-address-container" style="float:right;padding-right:0px;">
<div class="billing-address-container" style="float:right;padding-right:0px;">
@endif
@include('app.pdf.invoice.partials.billing-address')
</div>
@ -447,4 +417,5 @@
@include('app.pdf.invoice.partials.notes')
</div>
</body>
</html>

View File

@ -1,11 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title>Invoice</title>
{{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}}
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
/* -- Base -- */
body {
font-family: "DejaVu Sans";
}
@ -13,146 +15,134 @@
html {
margin: 0px;
padding: 0px;
margin-top: 50px;
}
table {
border-collapse: collapse;
}
.header-line {
color:rgba(0, 0, 0, 0.2);
position: absolute;
top: 80px;
left: 0px;
right: -70px;
width: 100%;
}
hr {
color:rgba(0, 0, 0, 0.2);
color: rgba(0, 0, 0, 0.2);
border: 0.5px solid #EAF1FB;
}
.items-table-hr{
margin: 0 30px 0 30px;
/* -- Header -- */
.header-bottom-divider {
color: rgba(0, 0, 0, 0.2);
position: absolute;
top: 100px;
left: 0px;
width: 100%;
}
.header-left {
.header-section-left {
padding-top: 45px;
padding-bottom: 45px;
padding-left: 30px;
display:inline-block;
width:30%;
display: inline-block;
width: 30%;
}
.header-table {
.header-container {
position: absolute;
width: 100%;
height: 150px;
left: 0px;
top: -60px;
}
.header-logo {
position: absolute;
height: 50px;
text-transform: capitalize;
color: #817AE3;
}
.header-right {
display:inline-block;
.header-section-right {
display: inline-block;
position: absolute;
right:0;
right: 0;
padding: 15px 30px 15px 0px;
float: right;
}
.inv-flex{
display:flex;
}
.inv-data{
text-align:right;
margin-right:120px;
}
.inv-value{
text-align:left;
margin-left:160px;
}
.header {
font-size: 20px;
color: rgba(0, 0, 0, 0.7);
}
.TextColor1 {
font-size: 16px;
color: rgba(0, 0, 0, 0.5);
/* -- Company Address */
.company-address-container {
width: auto;
text-transform: capitalize;
margin-bottom: 2px;
}
@page {
margin-top: 60px !important;
.company-address-container h1 {
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
margin-bottom: 0px;
margin-top: 10px;
}
.wrapper {
.company-address {
margin-top: 2px;
font-size: 12px;
line-height: 15px;
color: #595959;
}
/* -- Content Wrapper */
.content-wrapper {
display: block;
padding-top: 50px;
padding-top: 100px;
padding-bottom: 20px;
}
.address {
display: inline-block;
padding-top: 100px;
.main-content {
}
.bill-add {
.customer-address-container {
display: block;
float:left;
width:40%;
float: left;
width: 40%;
padding: 0 0 0 30px;
}
.company {
padding-left: 30px;
display: inline;
/* -- Shipping -- */
.shipping-address-container {
float:right;
display: block;
}
.shipping-address-container--left {
float:left;
width:30%;
display: block;
padding-left: 0;
}
.company h1 {
font-style: normal;
font-weight: bold;
font-size: 18px;
line-height: 22px;
letter-spacing: 0.05em;
}
.company-add {
text-align: left;
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
margin: 0px;
}
/* -------------------------- */
/* shipping style */
.ship-to {
.shipping-address-label {
padding-top: 5px;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
margin-bottom: 0px;
}
.ship-user-name {
.shipping-address-name {
padding: 0px;
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
margin: 0px;
max-width: 160px;
}
.ship-user-address {
font-style: normal;
font-weight: normal;
.shipping-address {
font-size: 10px;
line-height: 15px;
color: #595959;
@ -160,237 +150,156 @@
width: 160px;
}
.ship-user-phone {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
margin: 0px;
/* -- Billing -- */
.billing-address-container {
display: block;
float: left;
}
/* -------------------------- */
/* billing style */
.bill-to {
.billing-address-label {
padding-top: 5px;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
margin-bottom: 0px;
}
.bill-user-name {
.billing-address-name {
padding: 0px;
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
margin: 0px;
max-width: 160px;
}
.bill-user-address {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
margin:0px;
width: 160px;
}
.bill-user-phone {
font-style: normal;
font-weight: normal;
.billing-address {
font-size: 10px;
line-height: 15px;
color: #595959;
margin: 0px;
width: 160px;
}
/* -- Estimate Details -- */
.job-add {
.invoice-details-container {
display: block;
float: right;
padding: 20px 30px 0 0;
}
.amount-due {
background-color: #f2f2f2;
}
.textRight {
text-align: right;
}
.textLeft {
.attribute-label {
font-size: 12px;
line-height: 18px;
text-align: left;
color: #55547A
}
.textStyle1 {
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
}
.textStyle2 {
font-style: normal;
font-weight: normal;
.attribute-value {
font-size: 12px;
line-height: 18px;
text-align: right;
}
.main-table-header td {
padding: 10px;
}
.main-table-header {
border-bottom: 1px solid red;
}
tr.main-table-header th {
font-style: normal;
font-weight: 600;
font-size: 12px;
line-height: 18px;
}
tr.item-details td {
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
}
.table2 {
/* -- Items Table -- */
.items-table {
margin-top: 35px;
padding: 0px 30px 10px 30px;
page-break-before: avoid;
page-break-after: auto;
}
.table2 hr {
height:0.1px;
.items-table hr {
height: 0.1px;
}
.ItemTableHeader {
.item-table-heading {
font-size: 13.5;
text-align: center;
color: rgba(0, 0, 0, 0.85);
padding: 5px;
color: #55547A;
}
.items {
tr.item-table-heading-row th {
border-bottom: 0.620315px solid #E8E8E8;
font-size: 12px;
line-height: 18px;
}
tr.item-row td {
font-size: 12px;
line-height: 18px;
}
.item-cell {
font-size: 13;
color: rgba(0, 0, 0, 0.6);
text-align: center;
padding: 5px;
padding-top: 10px;
color: #040405;
}
.note-header {
font-size: 13;
color: rgba(0, 0, 0, 0.6);
.item-description {
color: #595959;
font-size: 9px;
line-height: 12px;
}
.note-text {
font-size: 10;
color: rgba(0, 0, 0, 0.6);
.item-cell-table-hr {
margin: 0 30px 0 30px;
}
.padd8 {
padding-top: 8px;
padding-bottom: 8px;
/* -- Total Display Table -- */
.total-display-container {
padding: 0 25px;
}
.padd2 {
.total-display-table {
box-sizing: border-box;
page-break-inside: avoid;
page-break-before: auto;
page-break-after: auto;
margin-left: 500px;
margin-top: 20px;
}
.total-table-attribute-label {
font-size: 12px;
color: #55547A;
text-align: left;
padding-left: 10px;
}
.total-table-attribute-value {
font-weight: bold;
text-align: right;
font-size: 12px;
color: #040405;
padding-right: 10px;
padding-top: 2px;
padding-bottom: 2px;
}
.table3 {
border: 1px solid #EAF1FB;
border-top: none;
box-sizing: border-box;
width: 630px;
page-break-inside: avoid;
page-break-before: auto;
page-break-after: auto;
.total-border-left {
border: 1px solid #E8E8E8 !important;
border-right: 0px !important;
padding-top: 0px;
padding: 8px !important;
}
.text-per-item-table3 {
border: 1px solid #EAF1FB;
border-top: none;
padding-right: 30px;
box-sizing: border-box;
width: 260px;
/* height: 100px; */
position: absolute;
right: -25;
}
td.invoice-total1 {
text-align:left;
padding: 15px 0 15px 10px;
font-size:12px;
line-height: 18px;
color: #55547A;
border-bottom:1px solid #E8E8E8;
border-top:1px solid #E8E8E8;
border-left:1px solid #E8E8E8;
}
td.invoice-total2 {
font-weight: 500;
text-align: right;
font-size:12px;
line-height: 18px;
padding: 15px 10px 15px 0;
color: #5851DB;
border-bottom:1px solid #E8E8E8;
border-top:1px solid #E8E8E8;
border-right:1px solid #E8E8E8;
}
.inv-item {
border-color: #d9d9d9;
}
.no-border {
border: none;
}
.desc {
font-weight: 100;
text-align: justify;
font-size: 10px;
margin-bottom: 15px;
margin-top:7px;
color:rgba(0, 0, 0, 0.85);
}
.company-details h1 {
margin:0;
font-style: normal;
font-weight: bold;
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
text-align: left;
max-width: 220px;
}
.company-details h4 {
margin:0;
font-style: normal;
font-weight: 100;
font-size: 18px;
line-height: 25px;
text-align: right;
}
.company-details h3 {
margin-bottom:1px;
margin-top:0;
}
tr.total td {
border-bottom:1px solid #E8E8E8;
border-top:1px solid #E8E8E8;
.total-border-right {
border: 1px solid #E8E8E8 !important;
border-left: 0px !important;
padding-top: 0px;
padding: 8px !important;
}
/* -- Notes -- */
.notes {
font-style: normal;
font-weight: 300;
font-size: 12px;
color: #595959;
margin-top: 15px;
@ -401,8 +310,6 @@
}
.notes-label {
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
@ -412,60 +319,113 @@
padding-bottom: 10px;
}
/* -- Helpers -- */
.text-primary {
color: #5851DB;
}
.text-center {
text-align: center
}
table .text-left {
text-align: left;
}
table .text-right {
text-align: right;
}
.border-0 {
border: none;
}
.py-2 {
padding-top: 2px;
padding-bottom: 2px;
}
.py-8 {
padding-top: 8px;
padding-bottom: 8px;
}
.py-3 {
padding: 3px 0;
}
.pr-20 {
padding-right: 20px;
}
.pr-10 {
padding-right: 10px;
}
.pl-20 {
padding-left: 20px;
}
.pl-10 {
padding-left: 10px;
}
.pl-0 {
padding-left: 0;
}
</style>
</head>
<body>
<div class="header-table">
<div class="header-container">
<table width="100%">
<tr>
<td class="header-section-left">
@if($logo)
<td class="header-left">
<img class="header-logo" src="{{ $logo }}" alt="Company Logo">
@else
@if($invoice->user->company)
<td class="header-left" style="padding-top:0px;">
<h1 class="header-logo"> {{$invoice->user->company->name}} </h1>
@endif
@endif
</td>
<td class="header-right company-details">
<td class="header-section-right company-address-container">
@include('app.pdf.invoice.partials.company-address')
</td>
</tr>
</table>
</div>
<hr class="header-line">
<hr class="header-bottom-divider">
<div class="wrapper">
<div class="address">
<div class="bill-add">
<div style="float:left;">
<div class="content-wrapper">
<div class="main-content">
<div class="customer-address-container">
<div class="billing-address-container">
@include('app.pdf.invoice.partials.billing-address')
</div>
@if($invoice->user->billingaddress)
<div style="float:right;">
<div class="shipping-address-container">
@else
<div style="float:left;">
<div class="shipping-address-container--left">
@endif
@include('app.pdf.invoice.partials.shipping-address')
</div>
<div style="clear: both;"></div>
</div>
<div class="job-add">
<div class="invoice-details-container">
<table>
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Invoice Number</td>
<td class="textStyle2"> &nbsp;{{$invoice->invoice_number}}</td>
<td class="attribute-label">Invoice Number</td>
<td class="attribute-value"> &nbsp;{{$invoice->invoice_number}}</td>
</tr>
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Invoice Date </td>
<td class="textStyle2"> &nbsp;{{$invoice->formattedInvoiceDate}}</td>
<td class="attribute-label">Invoice Date </td>
<td class="attribute-value"> &nbsp;{{$invoice->formattedInvoiceDate}}</td>
</tr>
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Due date</td>
<td class="textStyle2"> &nbsp;{{$invoice->formattedDueDate}}</td>
<td class="attribute-label">Due date</td>
<td class="attribute-value"> &nbsp;{{$invoice->formattedDueDate}}</td>
</tr>
</table>
</div>
@ -474,5 +434,7 @@
@include('app.pdf.invoice.partials.table')
@include('app.pdf.invoice.partials.notes')
</div>
</div>
</body>
</html>

View File

@ -1,11 +1,11 @@
@if($invoice->user->billingaddress)
<p class="bill-to">Bill To,</p>
<p class="billing-address-label">Bill To,</p>
@if($invoice->user->billingaddress->name)
<p class="bill-user-name">
<p class="billing-address-name">
{{$invoice->user->billingaddress->name}}
</p>
@endif
<p class="bill-user-address">
<p class="billing-address">
@if($invoice->user->billingaddress->address_street_1)
{!! nl2br(htmlspecialchars($invoice->user->billingaddress->address_street_1)) !!}<br>
@endif
@ -25,7 +25,7 @@
{{$invoice->user->billingaddress->country->name}}<br>
@endif
@if($invoice->user->billingaddress->phone)
<p class="bill-user-phone">
<p class="billing-address">
Phone :{{$invoice->user->billingaddress->phone}}
</p>
@endif

View File

@ -3,7 +3,7 @@
@endif
@if($company_address)
<p class="company-add">
<p class="company-address">
@if($company_address->addresses[0]['address_street_1'])
{!! nl2br(htmlspecialchars($company_address->addresses[0]['address_street_1'])) !!} <br>
@endif

View File

@ -1,11 +1,11 @@
@if($invoice->user->shippingaddress)
<p class="ship-to">Ship To,</p>
<p class="shipping-address-label">Ship To,</p>
@if($invoice->user->shippingaddress->name)
<p class="ship-user-name">
<p class="shipping-address-name">
{{$invoice->user->shippingaddress->name}}
</p>
@endif
<p class="ship-user-address">
<p class="shipping-address">
@if($invoice->user->shippingaddress->address_street_1)
{!! nl2br(htmlspecialchars($invoice->user->shippingaddress->address_street_1)) !!}<br>
@endif
@ -30,8 +30,8 @@
{{$invoice->user->shippingaddress->country->name}}<br>
@endif
@if($invoice->user->phone)
<p class="ship-user-phone">
@if($invoice->user->shippingaddress->phone)
<p class="shipping-address">
Phone :{{$invoice->user->shippingaddress->phone}}
</p>
@endif

View File

@ -1,46 +1,49 @@
<table width="100%" class="table2" cellspacing="0" border="0">
<tr class="main-table-header">
<th width="2%" class="ItemTableHeader" style="text-align: right; color: #55547A; padding-right: 20px">#</th>
<th width="40%" class="ItemTableHeader" style="text-align: left; color: #55547A; padding-left: 0px">Items</th>
<th class="ItemTableHeader" style="text-align: right; color: #55547A; padding-right: 20px">Quantity</th>
<th class="ItemTableHeader" style="text-align: right; color: #55547A; padding-right: 20px">Price</th>
<table width="100%" class="items-table" cellspacing="0" border="0">
<tr class="item-table-heading-row">
<th width="2%" class="item-table-heading text-right pr-20">#</th>
<th width="40%" class="item-table-heading text-left pl-0">Items</th>
<th class="item-table-heading text-right pr-20">Quantity</th>
<th class="item-table-heading pr-20 text-right">Price</th>
@if($invoice->discount_per_item === 'YES')
<th class="ItemTableHeader" style="text-align: right; color: #55547A; padding-left: 10px">Discount</th>
<th class="item-table-heading text-right pl-10">Discount</th>
@endif
<th class="ItemTableHeader" style="text-align: right; color: #55547A;">Amount</th>
<th class="item-table-heading text-right">Amount</th>
</tr>
@php
$index = 1
@endphp
@foreach ($invoice->items as $item)
<tr class="item-details">
<tr class="item-row">
<td
class="inv-item items"
style="text-align: right; color: #040405; padding-right: 20px; vertical-align: top;"
class="item-cell text-right pr-20"
style="vertical-align: top;"
>
{{$index}}
</td>
<td
class="inv-item items"
style="text-align: left; color: #040405;padding-left: 0px"
class="item-cell text-left pl-0"
style="vertical-align: top;"
>
<span>{{ $item->name }}</span><br>
<span style="text-align: left; color: #595959; font-size: 9px; font-weight:300; line-height: 12px;">{!! nl2br(htmlspecialchars($item->description)) !!}</span>
<span class="item-description">{!! nl2br(htmlspecialchars($item->description)) !!}</span>
</td>
<td
class="inv-item items"
style="text-align: right; color: #040405; padding-right: 20px"
class="item-cell pr-20 text-right"
style="vertical-align: top;"
>
{{$item->quantity}}
</td>
<td
class="inv-item items"
style="text-align: right; color: #040405; padding-right: 20px"
class="item-cell text-right pr-20"
style="vertical-align: top;"
>
{!! format_money_pdf($item->price, $invoice->user->currency) !!}
</td>
@if($invoice->discount_per_item === 'YES')
<td class="inv-item items" style="text-align: right; color: #040405; padding-left: 10px">
<td
class="item-cell text-right pl-10"
style="vertical-align: top;"
>
@if($item->discount_type === 'fixed')
{!! format_money_pdf($item->discount_val, $invoice->user->currency) !!}
@endif
@ -50,8 +53,8 @@
</td>
@endif
<td
class="inv-item items"
style="text-align: right; color: #040405;"
class="item-cell text-right"
style="vertical-align: top;"
>
{!! format_money_pdf($item->total, $invoice->user->currency) !!}
</td>
@ -62,22 +65,24 @@
@endforeach
</table>
<hr class="items-table-hr">
<hr class="item-cell-table-hr">
<table width="100%" cellspacing="0px" style="margin-left:420px; margin-top: 10px" border="0" class="table3 @if(count($invoice->items) > 12) page-break @endif">
<div class="total-display-container">
<table width="100%" cellspacing="0px" border="0" class="total-display-table @if(count($invoice->items) > 12) page-break @endif">
<tr>
<td class="no-border" style="color: #55547A; padding-left:10px; font-size:12px;">Subtotal</td>
<td class="no-border items padd2"
style="padding-right:10px; text-align: right; font-size:12px; color: #040405; font-weight: 500;">{!! format_money_pdf($invoice->sub_total, $invoice->user->currency) !!}</td>
<td class="border-0 total-table-attribute-label">Subtotal</td>
<td class="border-0 item-cell py-2 total-table-attribute-value">
{!! format_money_pdf($invoice->sub_total, $invoice->user->currency) !!}
</td>
</tr>
@if ($invoice->tax_per_item === 'YES')
@for ($i = 0; $i < count($labels); $i++)
<tr>
<td class="no-border" style="padding-left:10px; text-align:left; font-size:12px; color: #55547A;">
<td class="border-0 total-table-attribute-label">
{{$labels[$i]}}
</td>
<td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px; color: #040405">
<td class="border-0 item-cell py-2 total-table-attribute-value">
{!! format_money_pdf($taxes[$i], $invoice->user->currency) !!}
</td>
</tr>
@ -85,10 +90,10 @@
@else
@foreach ($invoice->taxes as $tax)
<tr>
<td class="no-border" style="padding-left:10px; text-align:left; font-size:12px; color: #55547A;">
<td class="border-0 total-table-attribute-label">
{{$tax->name.' ('.$tax->percent.'%)'}}
</td>
<td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px; color: #040405">
<td class="border-0 item-cell py-2 total-table-attribute-value">
{!! format_money_pdf($tax->amount, $invoice->user->currency) !!}
</td>
</tr>
@ -97,7 +102,7 @@
@if ($invoice->discount_per_item === 'NO')
<tr>
<td class="no-border" style="padding-left:10px; text-align:left; font-size:12px; color: #55547A;">
<td class="border-0 total-table-attribute-label">
@if($invoice->discount_type === 'fixed')
Discount
@endif
@ -105,7 +110,7 @@
Discount ({{$invoice->discount}}%)
@endif
</td>
<td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px; color: #040405">
<td class="border-0 item-cell py-2 total-table-attribute-value" >
@if($invoice->discount_type === 'fixed')
{!! format_money_pdf($invoice->discount_val, $invoice->user->currency) !!}
@endif
@ -116,20 +121,18 @@
</tr>
@endif
<tr>
<td style="padding:3px 0px"></td>
<td style="padding:3px 0px"></td>
<td class="py-3"></td>
<td class="py-3"></td>
</tr>
<tr>
<td class="no-border total-border-left"
style="padding-left:10px; padding-bottom:10px; text-align:left; padding-top:20px; font-size:12px; color: #55547A;"
>
<label class="total-bottom"> Total </label>
<td class="border-0 total-border-left total-table-attribute-label">
Total
</td>
<td
class="no-border total-border-right items padd8"
style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px; padding-top:20px; color: #5851DB"
class="border-0 total-border-right item-cell py-8 total-table-attribute-value text-primary"
>
{!! format_money_pdf($invoice->total, $invoice->user->currency)!!}
</td>
</tr>
</table>
</table>
</div>

View File

@ -1,11 +1,11 @@
@if($payment->user->billingaddress)
<p class="bill-to">Received From:</p>
<p class="billing-address-label">Received From:</p>
@if($payment->user->billingaddress->name)
<p class="bill-user-name">
<p class="billing-address-name">
{{$payment->user->billingaddress->name}}
</p>
@endif
<p class="bill-user-address">
<p class="billing-address">
@if($payment->user->billingaddress->address_street_1)
{!! nl2br(htmlspecialchars($payment->user->billingaddress->address_street_1)) !!}<br>
@endif
@ -25,7 +25,7 @@
{{$payment->user->billingaddress->country->name}}<br>
@endif
@if($payment->user->billingaddress->phone)
<p class="bill-user-phone">
<p class="billing-address">
Phone :{{$payment->user->billingaddress->phone}}
</p>
@endif

View File

@ -3,7 +3,7 @@
@endif
@if($company_address)
<p class="company-add">
<p class="company-address">
@if($company_address->addresses[0]['address_street_1'])
{!! nl2br(htmlspecialchars($company_address->addresses[0]['address_street_1'])) !!} <br>
@endif

View File

@ -1,11 +1,11 @@
@if($payment->user->shippingaddress)
<p class="ship-to">Ship To,</p>
<p class="shipping-address-label">Ship To,</p>
@if($payment->user->shippingaddress->name)
<p class="ship-user-name">
<p class="shipping-address-name">
{{$payment->user->shippingaddress->name}}
</p>
@endif
<p class="ship-user-address">
<p class="shipping-address">
@if($payment->user->shippingaddress->address_street_1)
{!! nl2br(htmlspecialchars($payment->user->shippingaddress->address_street_1)) !!}<br>
@endif
@ -31,7 +31,7 @@
@endif
@if($payment->user->phone)
<p class="ship-user-phone">
<p class="shipping-address">
Phone :{{$payment->user->shippingaddress->phone}}
</p>
@endif

View File

@ -2,10 +2,10 @@
<html>
<head>
<title>Invoice</title>
{{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}}
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<style type="text/css">
/* -- Base -- */
body {
font-family: "DejaVu Sans";
}
@ -13,6 +13,7 @@
html {
margin: 0px;
padding: 0px;
margin-top: 50px;
}
table {
border-collapse: collapse;
@ -27,339 +28,48 @@
width: 100%;
}
.header-left {
padding-top: 45px;
padding-bottom: 45px;
padding-left: 30px;
display:inline-block;
width:30%;
}
.header-table {
/* -- Heeader -- */
.header-container {
position: absolute;
width: 100%;
height: 150px;
left: 0px;
top: -60px;
}
.header-section-left {
padding-top: 45px;
padding-bottom: 45px;
padding-left: 30px;
display:inline-block;
width:30%;
}
.header-logo {
position: absolute;
height: 50px;
text-transform: capitalize;
color: #817AE3;
}
.header-right {
.header-section-right {
display:inline-block;
position: absolute;
right:0;
padding: 15px 30px 15px 0px;
float: right;
}
.inv-flex{
display:flex;
}
.inv-data{
text-align:right;
margin-right:120px;
}
.inv-value{
text-align:left;
margin-left:160px;
}
.header {
font-size: 20px;
color: rgba(0, 0, 0, 0.7);
}
.TextColor1 {
font-size: 16px;
color: rgba(0, 0, 0, 0.5);
}
/* -- Company Address -- */
@page {
margin-top: 60px !important;
}
.wrapper {
display: block;
height: 200px;
}
.address {
display: inline-block;
padding-top: 20px
}
.bill-add {
display: block;
float:left;
width:40%;
padding: 0 0 0 30px;
}
.company {
padding-left: 30px;
display: inline;
float:left;
width:30%;
}
.company h1 {
font-style: normal;
font-weight: bold;
font-size: 18px;
line-height: 22px;
letter-spacing: 0.05em;
}
.company-add {
text-align: left;
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
margin: 0px;
}
/* -------------------------- */
/* shipping style */
.ship-to {
padding-top: 5px;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
margin-bottom: 0px;
}
.ship-user-name {
padding: 0px;
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
margin: 0px;
}
.ship-user-address {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
margin: 0px;
width: 160px;
}
.ship-user-phone {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
margin: 0px;
}
/* -------------------------- */
/* billing style */
.bill-to {
padding-top: 5px;
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
margin-bottom: 0px;
color: #55547A;
}
.bill-user-name {
padding: 0px;
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
margin: 0px;
}
.bill-user-address {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
margin:0px;
width: 160px;
}
.bill-user-phone {
font-style: normal;
font-weight: normal;
font-size: 10px;
line-height: 15px;
color: #595959;
margin: 0px;
}
.job-add {
display: inline;
position: absolute;
float: right;
width: 40%;
height: 120px;
padding: 20px 30px 0 0;
}
.amount-due {
background-color: #f2f2f2;
}
.textRight {
text-align: right;
}
.textLeft {
text-align: left;
}
.textStyle1 {
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
}
.textStyle2 {
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
text-align: right;
}
.main-table-header td {
padding: 10px;
}
.main-table-header {
border-bottom: 1px solid red;
}
tr.main-table-header th {
font-style: normal;
font-weight: 600;
font-size: 12px;
line-height: 18px;
}
tr.item-details td {
font-style: normal;
font-weight: normal;
font-size: 12px;
line-height: 18px;
}
.table2 {
margin-top: 188px;
border-bottom: 1px solid #EAF1FB;
padding: 0px 30px 0 30px;
page-break-before: avoid;
page-break-after: auto;
}
.table2 hr {
height:0.1px;
}
.ItemTableHeader {
font-size: 13.5;
text-align: center;
color: rgba(0, 0, 0, 0.85);
padding: 5px;
}
.items {
font-size: 13;
color: rgba(0, 0, 0, 0.6);
text-align: center;
padding: 5px;
}
.note-header {
font-size: 13;
color: rgba(0, 0, 0, 0.6);
}
.note-text {
font-size: 10;
color: rgba(0, 0, 0, 0.6);
}
.padd8 {
padding-top: 8px;
padding-bottom: 8px;
}
.padd2 {
padding-top: 2px;
padding-bottom: 2px;
}
.table3 {
border: 1px solid #EAF1FB;
border-top: none;
box-sizing: border-box;
width: 630px;
page-break-inside: avoid;
page-break-before: auto;
page-break-after: auto;
}
.text-per-item-table3 {
border: 1px solid #EAF1FB;
border-top: none;
padding-right: 30px;
box-sizing: border-box;
width: 260px;
/* height: 100px; */
position: absolute;
right: -25;
}
td.invoice-total1 {
text-align:left;
padding: 15px 0 15px 10px;
font-size:12px;
line-height: 18px;
color: #55547A;
border-bottom:1px solid #E8E8E8;
border-top:1px solid #E8E8E8;
border-left:1px solid #E8E8E8;
}
td.invoice-total2 {
font-weight: 500;
text-align: right;
font-size:12px;
line-height: 18px;
padding: 15px 10px 15px 0;
color: #5851DB;
border-bottom:1px solid #E8E8E8;
border-top:1px solid #E8E8E8;
border-right:1px solid #E8E8E8;
}
.inv-item {
border-color: #d9d9d9;
}
.no-border {
border: none;
}
.desc {
font-weight: 100;
text-align: justify;
font-size: 10px;
margin-bottom: 15px;
margin-top:7px;
color:rgba(0, 0, 0, 0.85);
}
.company-details h1 {
margin:0;
font-style: normal;
font-weight: bold;
font-size: 15px;
line-height: 22px;
@ -367,26 +77,117 @@
text-align: left;
max-width: 220px;
}
.company-details h4 {
margin:0;
font-style: normal;
font-weight: 100;
font-size: 18px;
line-height: 25px;
text-align: right;
}
.company-details h3 {
margin-bottom:1px;
margin-top:0;
}
tr.total td {
border-bottom:1px solid #E8E8E8;
border-top:1px solid #E8E8E8;
.company-address{
text-align: left;
font-size: 10px;
line-height: 15px;
color: #595959;
margin: 0px;
}
.content-wrapper {
display: block;
height: 200px;
}
.main-content {
display: inline-block;
padding-top: 20px
}
/* -- Customer Address -- */
.customer-address-container {
display: block;
float:left;
width:40%;
padding: 0 0 0 30px;
}
/* -- Shipping -- */
.shipping-address-label {
padding-top: 5px;
font-size: 12px;
line-height: 18px;
margin-bottom: 0px;
}
.shipping-address-name {
padding: 0px;
font-size: 15px;
line-height: 22px;
margin: 0px;
}
.shipping-address {
font-size: 10px;
line-height: 15px;
color: #595959;
margin: 0px;
width: 160px;
}
/* -- Billing -- */
.billing-address-container {
float: left;
}
.billing-address-container--right {
float: right;
}
.billing-address-label {
padding-top: 5px;
font-size: 12px;
line-height: 18px;
margin-bottom: 0px;
color: #55547A;
}
.billing-address-name {
padding: 0px;
font-size: 15px;
line-height: 22px;
margin: 0px;
}
.billing-address {
font-size: 10px;
line-height: 15px;
color: #595959;
margin:0px;
width: 160px;
}
/* -- Payment Details -- */
.payment-details-container {
display: inline;
position: absolute;
float: right;
width: 40%;
height: 120px;
padding: 20px 30px 0 0;
}
.attribute-label {
font-size: 12px;
line-height: 18px;
text-align: left;
color: #55547A
}
.attribute-value {
font-size: 12px;
line-height: 18px;
text-align: right;
}
/* -- Notes -- */
.notes {
font-style: normal;
font-weight: 300;
font-size: 12px;
color: #595959;
margin-top: 15px;
@ -397,8 +198,6 @@
}
.notes-label {
font-style: normal;
font-weight: normal;
font-size: 15px;
line-height: 22px;
letter-spacing: 0.05em;
@ -408,7 +207,7 @@
padding-bottom: 10px;
}
.content-header {
.content-heading {
margin-top: 120px;
width: 100%;
text-align: center;
@ -419,14 +218,17 @@
margin: 0 0 0 0;
}
.content-header span {
font-weight: 500;
.content-heading span {
font-weight: 400;
font-size: 14px;
line-height: 25px;
padding-bottom: 5px;
border-bottom: 1px solid #B9C1D1;
}
.total-amount {
/* -- Total Display Box -- */
.total-display-box {
width: 315px;
display: block;
margin-right: 30px;
@ -437,7 +239,7 @@
padding: 12px 15px 15px 15px;
}
.total-amount-label {
.total-display-label {
display: inline;
font-weight: 600;
font-size: 14px;
@ -445,7 +247,7 @@
color: #595959;
}
.total-amount span {
.total-display-box span {
float: right;
font-weight: 500;
font-size: 14px;
@ -453,62 +255,64 @@
text-align: right;
color: #5851D8;
}
</style>
</head>
<body>
<div class="header-table">
<div class="header-container">
<table width="100%">
<tr>
@if($logo)
<td class="header-left">
<td class="header-section-left">
<img class="header-logo" src="{{ $logo }}" alt="Company Logo">
@else
@if($payment->user->company)
<td class="header-left" style="padding-top:0px;">
<td class="header-section-left" style="padding-top:0px;">
<h1 class="header-logo"> {{$payment->user->company->name}} </h1>
@endif
@endif
</td>
<td class="header-right company-details">
<td class="header-section-right company-details">
@include('app.pdf.payment.partials.company-address')
</td>
</tr>
</table>
</div>
<hr style="border: 0.620315px solid #E8E8E8;">
<p class="content-header">
<p class="content-heading">
<span>PAYMENT RECEIPT</span>
</p>
<div class="wrapper">
<div class="address">
<div class="bill-add">
<div style="float:left;">
<div class="content-wrapper">
<div class="main-content">
<div class="customer-address-container">
<div class="billing-address-container">
@include('app.pdf.payment.partials.billing-address')
</div>
<div style="float:right;">
<div class="billing-address-container--right">
</div>
<div style="clear: both;"></div>
</div>
<div class="job-add">
<div class="payment-details-container">
<table width="100%">
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Payment Date</td>
<td class="textStyle2"> &nbsp;{{$payment->formattedPaymentDate}}</td>
<td class="attribute-label">Payment Date</td>
<td class="attribute-value"> &nbsp;{{$payment->formattedPaymentDate}}</td>
</tr>
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Payment Number</td>
<td class="textStyle2"> &nbsp;{{$payment->payment_number}}</td>
<td class="attribute-label">Payment Number</td>
<td class="attribute-value"> &nbsp;{{$payment->payment_number}}</td>
</tr>
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Payment Mode</td>
<td class="textStyle2"> &nbsp;{{$payment->paymentMethod ? $payment->paymentMethod->name : '-'}}</td>
<td class="attribute-label">Payment Mode</td>
<td class="attribute-value"> &nbsp;{{$payment->paymentMethod ? $payment->paymentMethod->name : '-'}}</td>
</tr>
@if ($payment->invoice && $payment->invoice->invoice_number)
<tr>
<td class="textStyle1" style="text-align: left; color: #55547A">Invoice</td>
<td class="textStyle2"> &nbsp;{{$payment->invoice->invoice_number}}</td>
<td class="attribute-label">Invoice</td>
<td class="attribute-value"> &nbsp;{{$payment->invoice->invoice_number}}</td>
</tr>
@endif
</table>
@ -516,8 +320,8 @@
</div>
<div style="clear: both;"></div>
</div>
<div class="total-amount">
<p class="total-amount-label">Amount Received</p>
<div class="total-display-box">
<p class="total-display-label">Amount Received</p>
<span>{!! format_money_pdf($payment->amount, $payment->user->currency) !!}</span>
</div>
</body>

View File

@ -2,35 +2,24 @@
<html lang="en">
<head>
<title>Expenses Report</title>
{{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}}
<style type="text/css">
body {
font-family: "DejaVu Sans";
}
/* html {
margin: 0px;
padding: 0px;
} */
table {
border-collapse: collapse;
}
.main-container {
/* padding: 30px 60px; */
}
.sub-container{
padding: 0px 20px;
}
.header {
.report-header {
width: 100%;
}
.heading-text {
font-style: normal;
font-weight: 600;
font-size: 24px;
color: #5851D8;
@ -41,7 +30,6 @@
}
.heading-date-range {
font-style: normal;
font-weight: 600;
font-size: 15px;
color: #A5ACC1;
@ -52,10 +40,8 @@
}
.sub-heading-text {
font-style: normal;
font-weight: 600;
font-size: 16px;
/* line-height: 21px; */
color: #595959;
padding: 0px;
margin: 0px;
@ -65,8 +51,6 @@
.expenses-title {
margin-top: 60px;
padding-left: 3px;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 21px;
color: #040405;
@ -84,18 +68,14 @@
.expense-title {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 21px;
color: #595959;
}
.expense-money {
.expense-amount {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 21px;
text-align: right;
@ -118,7 +98,6 @@
padding: 0px;
margin: 0px;
text-align: right;
font-style: normal;
font-weight: 500;
font-size: 16px;
line-height: 21px;
@ -126,7 +105,7 @@
color: #040405;
}
.total-expense-table {
.report-footer {
width: 100%;
margin-top: 40px;
padding: 15px 20px;
@ -134,22 +113,20 @@
box-sizing: border-box;
}
.total-expense-title {
.report-footer-label {
padding: 0px;
margin: 0px;
text-align: left;
font-style: normal;
font-weight: 600;
font-size: 16px;
line-height: 21px;
color: #595959;
}
.total-expense-money {
.report-footer-value {
padding: 0px;
margin: 0px;
text-align: right;
font-style: normal;
font-weight: 500;
font-size: 20px;
line-height: 21px;
@ -158,9 +135,8 @@
</style>
</head>
<body>
<div class="main-container">
<div class="sub-container">
<table class="header">
<table class="report-header">
<tr>
<td>
<p class="heading-text">{{ $company->name }}</p>
@ -186,7 +162,7 @@
</p>
</td>
<td>
<p class="expense-money">
<p class="expense-amount">
{!! format_money_pdf($expenseCategory->total_amount) !!}
</p>
</td>
@ -203,16 +179,15 @@
</td>
</tr>
</table>
<table class="total-expense-table">
<table class="report-footer">
<tr>
<td>
<p class="total-expense-title">TOTAL EXPENSE</p>
<p class="report-footer-label">TOTAL EXPENSE</p>
</td>
<td>
<p class="total-expense-money">{!! format_money_pdf($totalExpense) !!}</p>
<p class="report-footer-value">{!! format_money_pdf($totalExpense) !!}</p>
</td>
</tr>
</table>
</div>
</body>
</html>

View File

@ -2,35 +2,24 @@
<html lang="en">
<head>
<title>Profit & Loss Report</title>
{{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}}
<style type="text/css">
body {
font-family: "DejaVu Sans";
}
html {
margin: 0px;
padding: 0px;
}
table {
border-collapse: collapse;
}
.main-container {
padding: 30px 60px;
}
.sub-container{
padding: 0px 20px;
}
.header {
.report-header {
width: 100%;
}
.heading-text {
font-style: normal;
font-weight: 600;
font-size: 24px;
color: #5851D8;
@ -41,7 +30,6 @@
}
.heading-date-range {
font-style: normal;
font-weight: 600;
font-size: 15px;
color: #A5ACC1;
@ -52,10 +40,8 @@
}
.sub-heading-text {
font-style: normal;
font-weight: 600;
font-size: 16px;
/* line-height: 21px; */
color: #595959;
padding: 0px;
margin: 0px;
@ -70,18 +56,15 @@
.income-title {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 21px;
color: #040405;
text-align: left;
}
.income-money {
.income-amount {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: 500;
font-size: 16px;
line-height: 21px;
@ -93,8 +76,6 @@
.expenses-title {
margin-top: 20px;
padding-left: 3px;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 21px;
color: #040405;
@ -112,25 +93,21 @@
.expense-title {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 21px;
color: #595959;
}
.expense-money {
.expense-amount {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 21px;
text-align: right;
color: #595959;
}
.expense-total-table {
.expense-total-indicator-table {
border-top: 1px solid #EAF1FB;
width: 100%;
}
@ -146,7 +123,6 @@
padding: 0px;
margin: 0px;
text-align: right;
font-style: normal;
font-weight: 500;
font-size: 16px;
line-height: 21px;
@ -154,7 +130,7 @@
color: #040405;
}
.profit-table {
.report-footer {
width: 100%;
margin-top: 40px;
padding: 15px 20px;
@ -162,22 +138,20 @@
box-sizing: border-box;
}
.profit-title {
.report-footer-label {
padding: 0px;
margin: 0px;
text-align: left;
font-style: normal;
font-weight: 600;
font-size: 16px;
line-height: 21px;
color: #595959;
}
.profit-money {
.report-footer-value {
padding: 0px;
margin: 0px;
text-align: right;
font-style: normal;
font-weight: 500;
font-size: 20px;
line-height: 21px;
@ -186,9 +160,8 @@
</style>
</head>
<body>
<div class="main-container">
<div class="sub-container">
<table class="header">
<table class="report-header">
<tr>
<td>
<p class="heading-text">{{ $company->name }}</p>
@ -210,7 +183,7 @@
<p class="income-title">Income</p>
</td>
<td>
<p class="income-money">{!! format_money_pdf($income) !!}</p>
<p class="income-amount">{!! format_money_pdf($income) !!}</p>
</td>
</tr>
</table>
@ -225,7 +198,7 @@
</p>
</td>
<td>
<p class="expense-money">
<p class="expense-amount">
{!! format_money_pdf($expenseCategory->total_amount) !!}
</p>
</td>
@ -236,23 +209,22 @@
</div>
</div>
<table class="expense-total-table">
<table class="expense-total-indicator-table">
<tr>
<td class="expense-total-cell">
<p class="expense-total">{!! format_money_pdf($totalExpense) !!}</p>
</td>
</tr>
</table>
<table class="profit-table">
<table class="report-footer">
<tr>
<td>
<p class="profit-title">NET PROFIT</p>
<p class="report-footer-label">NET PROFIT</p>
</td>
<td>
<p class="profit-money">{!! format_money_pdf(($income-$totalExpense)) !!}</p>
<p class="report-footer-value">{!! format_money_pdf(($income-$totalExpense)) !!}</p>
</td>
</tr>
</table>
</div>
</body>
</html>

View File

@ -2,35 +2,24 @@
<html lang="en">
<head>
<title>Sales Customer Report</title>
{{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}}
<style type="text/css">
body {
font-family: "DejaVu Sans";
}
/* html {
margin: 0px;
padding: 0px;
} */
table {
border-collapse: collapse;
}
.main-container {
/* padding: 30px 80px; */
}
.sub-container{
padding: 0px 20px;
}
.header {
.report-header {
width: 100%;
}
.heading-text {
font-style: normal;
font-weight: 600;
font-size: 24px;
color: #5851D8;
@ -41,7 +30,6 @@
}
.heading-date-range {
font-style: normal;
font-weight: 600;
font-size: 15px;
color: #A5ACC1;
@ -52,7 +40,6 @@
}
.sub-heading-text {
font-style: normal;
font-weight: 600;
font-size: 16px;
line-height: 21px;
@ -62,90 +49,55 @@
margin-top: 30px;
}
.income-table {
margin-top: 53px;
width: 100%;
}
.income-title {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 21px;
color: #040405;
text-align: left;
}
.income-money {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: 500;
font-size: 16px;
line-height: 21px;
text-align: right;
color: #040405;
text-align: right;
}
.expenses-title {
.sales-customer-name {
margin-top: 20px;
padding-left: 3px;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 21px;
color: #040405;
}
.expenses-table-container {
.sales-table-container {
padding-left: 10px;
}
.expenses-table {
.sales-table {
width: 100%;
padding-bottom: 10px;
}
.expense-title {
.sales-information-text {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 21px;
color: #595959;
}
.expense-money {
.sales-amount {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 21px;
text-align: right;
color: #595959;
}
.expense-total-table {
.sales-total-indicator-table {
border-top: 1px solid #EAF1FB;
width: 100%;
}
.expense-total-cell {
.sales-total-cell {
padding-top: 10px;
}
.expense-total {
.sales-total-amount {
padding-top: 10px;
padding-right: 30px;
padding: 0px;
margin: 0px;
text-align: right;
font-style: normal;
font-weight: 500;
font-size: 16px;
line-height: 21px;
@ -153,7 +105,7 @@
color: #040405;
}
.profit-table {
.report-footer {
width: 100%;
margin-top: 40px;
padding: 15px 20px;
@ -161,22 +113,20 @@
box-sizing: border-box;
}
.profit-title {
.report-footer-label {
padding: 0px;
margin: 0px;
text-align: left;
font-style: normal;
font-weight: 600;
font-size: 16px;
line-height: 21px;
color: #595959;
}
.profit-money {
.report-footer-value {
padding: 0px;
margin: 0px;
text-align: right;
font-style: normal;
font-weight: 500;
font-size: 20px;
line-height: 21px;
@ -188,9 +138,8 @@
</style>
</head>
<body>
<div class="main-container">
<div class="sub-container">
<table class="header">
<table class="report-header">
<tr>
<td>
<p class="heading-text">{{ $company->name }}</p>
@ -206,29 +155,19 @@
</tr>
</table>
{{-- <table class="income-table">
<tr>
<td>
<p class="income-title">Income</p>
</td>
<td>
<p class="income-money">{{ $income }}</p>
</td>
</tr>
</table> --}}
@foreach ($customers as $customer)
<p class="expenses-title">{{ $customer->name }}</p>
<div class="expenses-table-container">
<table class="expenses-table">
<p class="sales-customer-name">{{ $customer->name }}</p>
<div class="sales-table-container">
<table class="sales-table">
@foreach ($customer->invoices as $invoice)
<tr>
<td>
<p class="expense-title">
<p class="sales-information-text">
{{ $invoice->formattedInvoiceDate }} ({{ $invoice->invoice_number }})
</p>
</td>
<td>
<p class="expense-money">
<p class="sales-amount">
{!! format_money_pdf($invoice->total) !!}
</p>
</td>
@ -236,10 +175,10 @@
@endforeach
</table>
</div>
<table class="expense-total-table">
<table class="sales-total-indicator-table">
<tr>
<td class="expense-total-cell">
<p class="expense-total">
<td class="sales-total-cell">
<p class="sales-total-amount">
{!! format_money_pdf($customer->totalAmount) !!}
</p>
</td>
@ -249,18 +188,17 @@
</div>
<table class="profit-table">
<table class="report-footer">
<tr>
<td>
<p class="profit-title">TOTAL SALES</p>
<p class="report-footer-label">TOTAL SALES</p>
</td>
<td>
<p class="profit-money">
<p class="report-footer-value">
{!! format_money_pdf($totalAmount) !!}
</p>
</td>
</tr>
</table>
</div>
</body>
</html>

View File

@ -2,35 +2,24 @@
<html lang="en">
<head>
<title>Sales Item Report</title>
{{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}}
<style type="text/css">
body {
font-family: "DejaVu Sans";
}
/* html {
margin: 0px;
padding: 0px;
} */
table {
border-collapse: collapse;
}
.main-container {
/* padding: 30px 80px; */
}
.sub-container{
padding: 0px 20px;
}
.header {
.report-header {
width: 100%;
}
.heading-text {
font-style: normal;
font-weight: 600;
font-size: 24px;
color: #5851D8;
@ -41,7 +30,6 @@
}
.heading-date-range {
font-style: normal;
font-weight: 600;
font-size: 15px;
color: #A5ACC1;
@ -52,7 +40,6 @@
}
.sub-heading-text {
font-style: normal;
font-weight: 600;
font-size: 16px;
line-height: 21px;
@ -62,90 +49,55 @@
margin-top: 30px;
}
.income-table {
margin-top: 53px;
width: 100%;
}
.income-title {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 21px;
color: #040405;
text-align: left;
}
.income-money {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: 500;
font-size: 16px;
line-height: 21px;
text-align: right;
color: #040405;
text-align: right;
}
.expenses-title {
.sales-items-title {
margin-top: 20px;
padding-left: 3px;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 21px;
color: #040405;
}
.expenses-table-container {
.items-table-container {
padding-left: 10px;
}
.expenses-table {
.items-table {
width: 100%;
padding-bottom: 10px;
}
.expense-title {
.item-title {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 21px;
color: #595959;
}
.expense-money {
.item-sales-amount {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 21px;
text-align: right;
color: #595959;
}
.expense-total-table {
.sales-total-indicator-table {
border-top: 1px solid #EAF1FB;
width: 100%;
}
.expense-total-cell {
.sales-total-cell {
padding-top: 10px;
}
.expense-total {
.sales-total-amount {
padding-top: 10px;
padding-right: 30px;
padding: 0px;
margin: 0px;
text-align: right;
font-style: normal;
font-weight: 500;
font-size: 16px;
line-height: 21px;
@ -153,7 +105,7 @@
color: #040405;
}
.profit-table {
.report-footer {
width: 100%;
margin-top: 40px;
padding: 15px 20px;
@ -161,22 +113,20 @@
box-sizing: border-box;
}
.profit-title {
.report-footer-label {
padding: 0px;
margin: 0px;
text-align: left;
font-style: normal;
font-weight: 600;
font-size: 16px;
line-height: 21px;
color: #595959;
}
.profit-money {
.report-footer-value {
padding: 0px;
margin: 0px;
text-align: right;
font-style: normal;
font-weight: 500;
font-size: 20px;
line-height: 21px;
@ -188,9 +138,8 @@
</style>
</head>
<body>
<div class="main-container">
<div class="sub-container">
<table class="header">
<table class="report-header">
<tr>
<td>
<p class="heading-text">{{ $company->name }}</p>
@ -206,28 +155,18 @@
</tr>
</table>
{{-- <table class="income-table">
<tr>
<td>
<p class="income-title">Income</p>
</td>
<td>
<p class="income-money">{{ $income }}</p>
</td>
</tr>
</table> --}}
<p class="expenses-title">Items</p>
<p class="sales-items-title">Items</p>
@foreach ($items as $item)
<div class="expenses-table-container">
<table class="expenses-table">
<div class="items-table-container">
<table class="items-table">
<tr>
<td>
<p class="expense-title">
<p class="item-title">
{{ $item->name }}
</p>
</td>
<td>
<p class="expense-money">
<p class="item-sales-amount">
{!! format_money_pdf($item->total_amount) !!}
</p>
</td>
@ -236,10 +175,10 @@
</div>
@endforeach
<table class="expense-total-table">
<table class="sales-total-indicator-table">
<tr>
<td class="expense-total-cell">
<p class="expense-total">
<td class="sales-total-cell">
<p class="sales-total-amount">
{!! format_money_pdf($totalAmount) !!}
</p>
</td>
@ -248,18 +187,17 @@
</div>
<table class="profit-table">
<table class="report-footer">
<tr>
<td>
<p class="profit-title">TOTAL SALES</p>
<p class="report-footer-label">TOTAL SALES</p>
</td>
<td>
<p class="profit-money">
<p class="report-footer-value">
{!! format_money_pdf($totalAmount) !!}
</p>
</td>
</tr>
</table>
</div>
</body>
</html>

View File

@ -2,36 +2,25 @@
<html lang="en">
<head>
<title>Tax Summary Report</title>
{{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}}
<style type="text/css">
body {
font-family: "DejaVu Sans";
}
/* html {
margin: 0px;
padding: 0px;
} */
table {
border-collapse: collapse;
}
.main-container {
/* padding: 30px 60px; */
}
.sub-container{
padding: 0px 20px;
}
.header {
.report-header {
width: 100%;
margin-bottom: 60px
}
.heading-text {
font-style: normal;
font-weight: 600;
font-size: 24px;
color: #5851D8;
@ -42,7 +31,6 @@
}
.heading-date-range {
font-style: normal;
font-weight: 600;
font-size: 15px;
color: #A5ACC1;
@ -53,31 +41,17 @@
}
.sub-heading-text {
font-style: normal;
font-weight: 600;
font-size: 16px;
/* line-height: 21px; */
color: #595959;
padding: 0px;
margin: 0px;
margin-top: 6px;
}
.types-title {
.tax-types-title {
margin-top: 20px;
padding-left: 3px;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 21px;
color: #040405;
}
.tax-title {
margin-top: 60px;
padding-left: 3px;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 21px;
color: #040405;
@ -95,18 +69,14 @@
.tax-title {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 21px;
color: #595959;
}
.tax-money {
.tax-amount {
padding: 0px;
margin: 0px;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 21px;
text-align: right;
@ -129,7 +99,6 @@
padding: 0px;
margin: 0px;
text-align: right;
font-style: normal;
font-weight: 500;
font-size: 16px;
line-height: 21px;
@ -137,7 +106,7 @@
color: #040405;
}
.total-tax-table {
.report-footer {
width: 100%;
margin-top: 40px;
padding: 15px 20px;
@ -145,22 +114,20 @@
box-sizing: border-box;
}
.total-tax-title {
.report-footer-label {
padding: 0px;
margin: 0px;
text-align: left;
font-style: normal;
font-weight: 600;
font-size: 16px;
line-height: 21px;
color: #595959;
}
.total-tax-money {
.report-footer-value {
padding: 0px;
margin: 0px;
text-align: right;
font-style: normal;
font-weight: 500;
font-size: 20px;
line-height: 21px;
@ -169,9 +136,8 @@
</style>
</head>
<body>
<div class="main-container">
<div class="sub-container">
<table class="header">
<table class="report-header">
<tr>
<td>
<p class="heading-text">
@ -190,7 +156,7 @@
</td>
</tr>
</table>
<p class="types-title">Tax Types</p>
<p class="tax-types-title">Tax Types</p>
<div class="tax-table-container">
<table class="tax-table">
@foreach ($taxTypes as $tax)
@ -201,7 +167,7 @@
</p>
</td>
<td>
<p class="tax-money">
<p class="tax-amount">
{!! format_money_pdf($tax->total_tax_amount) !!}
</p>
</td>
@ -221,18 +187,17 @@
</td>
</tr>
</table>
<table class="total-tax-table">
<table class="report-footer">
<tr>
<td>
<p class="total-tax-title">TOTAL TAX</p>
<p class="report-footer-label">TOTAL TAX</p>
</td>
<td>
<p class="total-tax-money">
<p class="report-footer-value">
{!! format_money_pdf($totalTaxAmount) !!}
</p>
</td>
</tr>
</table>
</div>
</body>
</html>

View File

@ -1,6 +1,6 @@
@component('mail::message')
# Introduction
Customer viewed this Estimate.
{{ $data['user']['name'] }} viewed this Estimate.
@component('mail::button', ['url' => url('/admin/estimates/'.$data['estimate']['id'].'/view')])
Estimate

View File

@ -1,6 +1,6 @@
@component('mail::message')
# Introduction
Customer viewed this Invoice.
{{ $data['user']['name'] }} viewed this Invoice.
@component('mail::button', ['url' => url('/admin/invoices/'.$data['invoice']['id'].'/view')])
Invoice

View File

@ -122,23 +122,41 @@ Route::group(['middleware' => 'api'], function () {
'middleware' => 'admin'
], function () {
// Auto update routes
// Self Update
//----------------------------------
Route::post('/update', [
'as' => 'auto.update',
'uses' => 'UpdateController@update'
Route::get('/check/update', [
'as' => 'update.check',
'uses' => 'UpdateController@checkLatestVersion'
]);
Route::post('/update/download', [
'as' => 'update.download',
'uses' => 'UpdateController@download'
]);
Route::post('/update/unzip', [
'as' => 'update.unzip',
'uses' => 'UpdateController@unzip'
]);
Route::post('/update/copy', [
'as' => 'update.copy',
'uses' => 'UpdateController@copyFiles'
]);
Route::post('/update/migrate', [
'as' => 'update.migrate',
'uses' => 'UpdateController@migrate'
]);
Route::post('/update/finish', [
'as' => 'auto.update.finish',
'as' => 'update.finish',
'uses' => 'UpdateController@finishUpdate'
]);
Route::get('/check/update', [
'as' => 'check.update',
'uses' => 'UpdateController@checkLatestVersion'
]);
// Bootstrap
//----------------------------------
Route::get('/bootstrap', [
'as' => 'bootstrap',

View File

@ -6,6 +6,7 @@
|--------------------------------------------------------------------------
|
*/
Route::group(['prefix' => 'reports'], function () {
// sales report by customer
@ -46,7 +47,6 @@ Route::group(['prefix' => 'reports'], function () {
'as' => 'get.profit.loss',
'uses' => 'ReportController@profitLossReport'
]);
});
@ -88,7 +88,7 @@ Route::get('/expenses/{id}/receipt/{hash}', [
'uses' => 'ExpensesController@downloadReceipt'
]);
// Setup for instalation of app
// Setup for installation of app
// ----------------------------------------------
Route::get('/on-boarding', function () {
return view('app');