mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-27 11:41:09 -04:00
Merge branch 'payment_receipt' into 'master'
This commit is contained in:
51
app/Console/Commands/ResetApp.php
Normal file
51
app/Console/Commands/ResetApp.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
|
||||
class ResetApp extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'reset:app';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Clean database, database_created and public/storage folder';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if ($this->confirm('Do you wish to continue? This will delete your tables')) {
|
||||
Artisan::call('migrate:reset --force');
|
||||
|
||||
\Storage::disk('local')->delete('database_created');
|
||||
|
||||
$file = new Filesystem;
|
||||
$file->cleanDirectory('storage/app/public');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,7 @@ class Kernel extends ConsoleKernel
|
||||
* @var array
|
||||
*/
|
||||
protected $commands = [
|
||||
|
||||
Commands\ResetApp::class
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@ -19,7 +19,7 @@ use Crater\Currency;
|
||||
use Crater\CompanySetting;
|
||||
|
||||
class CompanyController extends Controller
|
||||
{
|
||||
{
|
||||
/**
|
||||
* Retrive the Admin account.
|
||||
* @return \Crater\User
|
||||
@ -66,9 +66,9 @@ class CompanyController extends Controller
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get Admin Account alongside the country from the addresses table and
|
||||
* Get Admin Account alongside the country from the addresses table and
|
||||
* The company from companies table
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
@ -148,6 +148,7 @@ class CompanyController extends Controller
|
||||
["code"=>"fr", "name" => "French"],
|
||||
["code"=>"es", "name" => "Spanish"],
|
||||
["code"=>"ar", "name" => "العربية"],
|
||||
["code"=>"de", "name" => "German"]
|
||||
];
|
||||
|
||||
return response()->json([
|
||||
@ -191,7 +192,7 @@ class CompanyController extends Controller
|
||||
'success' => true
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function getCustomizeSetting (Request $request)
|
||||
{
|
||||
$invoice_prefix = CompanySetting::getSetting('invoice_prefix', $request->header('company'));
|
||||
|
||||
@ -406,6 +406,10 @@ class EstimatesController extends Controller
|
||||
{
|
||||
$estimate = Estimate::with(['items', 'items.taxes', 'user', 'estimateTemplate', 'taxes'])->find($id);
|
||||
$invoice_date = Carbon::parse($estimate->estimate_date);
|
||||
$invoice_prefix = CompanySetting::getSetting(
|
||||
'invoice_prefix',
|
||||
$request->header('company')
|
||||
);
|
||||
$due_date = Carbon::parse($estimate->estimate_date)->addDays(7);
|
||||
$tax_per_item = CompanySetting::getSetting(
|
||||
'tax_per_item',
|
||||
@ -425,7 +429,7 @@ class EstimatesController extends Controller
|
||||
$invoice = Invoice::create([
|
||||
'invoice_date' => $invoice_date,
|
||||
'due_date' => $due_date,
|
||||
'invoice_number' => "INV-".Invoice::getNextInvoiceNumber(),
|
||||
'invoice_number' => $invoice_prefix."-".Invoice::getNextInvoiceNumber($invoice_prefix),
|
||||
'reference_number' => $estimate->reference_number,
|
||||
'user_id' => $estimate->user_id,
|
||||
'company_id' => $request->header('company'),
|
||||
|
||||
@ -6,6 +6,7 @@ use Crater\Invoice;
|
||||
use PDF;
|
||||
use Crater\CompanySetting;
|
||||
use Crater\Estimate;
|
||||
use Crater\Payment;
|
||||
use Crater\User;
|
||||
use Crater\Company;
|
||||
use Crater\InvoiceTemplate;
|
||||
@ -376,4 +377,34 @@ class FrontendController extends Controller
|
||||
|
||||
return $pdf->stream();
|
||||
}
|
||||
|
||||
public function getPaymentPdf($id)
|
||||
{
|
||||
$payment = Payment::with([
|
||||
'user',
|
||||
'invoice',
|
||||
'paymentMethod'
|
||||
])
|
||||
->where('unique_hash', $id)
|
||||
->first();
|
||||
|
||||
$company = Company::find($payment->company_id);
|
||||
$companyAddress = User::with(['addresses', 'addresses.country'])->find(1);
|
||||
|
||||
$logo = $company->getMedia('logo')->first();
|
||||
|
||||
if($logo) {
|
||||
$logo = $logo->getFullUrl();
|
||||
}
|
||||
|
||||
view()->share([
|
||||
'payment' => $payment,
|
||||
'company_address' => $companyAddress,
|
||||
'logo' => $logo ?? null
|
||||
]);
|
||||
|
||||
$pdf = PDF::loadView('app.pdf.payment.payment');
|
||||
|
||||
return $pdf->stream();
|
||||
}
|
||||
}
|
||||
|
||||
@ -497,4 +497,94 @@ class InvoicesController extends Controller
|
||||
'invoices' => $invoices
|
||||
]);
|
||||
}
|
||||
|
||||
public function cloneInvoice(Request $request)
|
||||
{
|
||||
$oldInvoice = Invoice::with([
|
||||
'items.taxes',
|
||||
'user',
|
||||
'invoiceTemplate',
|
||||
'taxes.taxType'
|
||||
])
|
||||
->find($request->id);
|
||||
|
||||
$date = Carbon::now();
|
||||
$invoice_prefix = CompanySetting::getSetting(
|
||||
'invoice_prefix',
|
||||
$request->header('company')
|
||||
);
|
||||
$tax_per_item = CompanySetting::getSetting(
|
||||
'tax_per_item',
|
||||
$request->header('company')
|
||||
) ? CompanySetting::getSetting(
|
||||
'tax_per_item',
|
||||
$request->header('company')
|
||||
) : 'NO';
|
||||
$discount_per_item = CompanySetting::getSetting(
|
||||
'discount_per_item',
|
||||
$request->header('company')
|
||||
) ? CompanySetting::getSetting(
|
||||
'discount_per_item',
|
||||
$request->header('company')
|
||||
) : 'NO';
|
||||
|
||||
$invoice = Invoice::create([
|
||||
'invoice_date' => $date,
|
||||
'due_date' => $date,
|
||||
'invoice_number' => $invoice_prefix."-".Invoice::getNextInvoiceNumber($invoice_prefix),
|
||||
'reference_number' => $oldInvoice->reference_number,
|
||||
'user_id' => $oldInvoice->user_id,
|
||||
'company_id' => $request->header('company'),
|
||||
'invoice_template_id' => 1,
|
||||
'status' => Invoice::STATUS_DRAFT,
|
||||
'paid_status' => Invoice::STATUS_UNPAID,
|
||||
'sub_total' => $oldInvoice->sub_total,
|
||||
'discount' => $oldInvoice->discount,
|
||||
'discount_type' => $oldInvoice->discount_type,
|
||||
'discount_val' => $oldInvoice->discount_val,
|
||||
'total' => $oldInvoice->total,
|
||||
'due_amount' => $oldInvoice->total,
|
||||
'tax_per_item' => $oldInvoice->tax_per_item,
|
||||
'discount_per_item' => $oldInvoice->discount_per_item,
|
||||
'tax' => $oldInvoice->tax,
|
||||
'notes' => $oldInvoice->notes,
|
||||
'unique_hash' => str_random(60)
|
||||
]);
|
||||
|
||||
$invoiceItems = $oldInvoice->items->toArray();
|
||||
|
||||
foreach ($invoiceItems as $invoiceItem) {
|
||||
$invoiceItem['company_id'] = $request->header('company');
|
||||
$invoiceItem['name'] = $invoiceItem['name'];
|
||||
$item = $invoice->items()->create($invoiceItem);
|
||||
|
||||
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
|
||||
foreach ($invoiceItem['taxes'] as $tax) {
|
||||
$tax['company_id'] = $request->header('company');
|
||||
|
||||
if ($tax['amount']) {
|
||||
$item->taxes()->create($tax);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($oldInvoice->taxes) {
|
||||
foreach ($oldInvoice->taxes->toArray() as $tax) {
|
||||
$tax['company_id'] = $request->header('company');
|
||||
$invoice->taxes()->create($tax);
|
||||
}
|
||||
}
|
||||
|
||||
$invoice = Invoice::with([
|
||||
'items',
|
||||
'user',
|
||||
'invoiceTemplate',
|
||||
'taxes'
|
||||
])->find($invoice->id);
|
||||
|
||||
return response()->json([
|
||||
'invoice' => $invoice
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,14 +14,17 @@ class ItemsController extends Controller
|
||||
{
|
||||
$limit = $request->has('limit') ? $request->limit : 10;
|
||||
|
||||
$items = Item::applyFilters($request->only([
|
||||
$items = Item::with(['taxes'])
|
||||
->leftJoin('units', 'units.id', '=', 'items.unit_id')
|
||||
->applyFilters($request->only([
|
||||
'search',
|
||||
'price',
|
||||
'unit',
|
||||
'unit_id',
|
||||
'orderByField',
|
||||
'orderBy'
|
||||
]))
|
||||
->whereCompany($request->header('company'))
|
||||
->select('items.*', 'units.name as unit_name')
|
||||
->latest()
|
||||
->paginate($limit);
|
||||
|
||||
@ -33,7 +36,7 @@ class ItemsController extends Controller
|
||||
|
||||
public function edit(Request $request, $id)
|
||||
{
|
||||
$item = Item::with('taxes')->find($id);
|
||||
$item = Item::with(['taxes', 'unit'])->find($id);
|
||||
|
||||
return response()->json([
|
||||
'item' => $item,
|
||||
@ -54,7 +57,7 @@ class ItemsController extends Controller
|
||||
{
|
||||
$item = new Item();
|
||||
$item->name = $request->name;
|
||||
$item->unit = $request->unit;
|
||||
$item->unit_id = $request->unit_id;
|
||||
$item->description = $request->description;
|
||||
$item->company_id = $request->header('company');
|
||||
$item->price = $request->price;
|
||||
@ -85,7 +88,7 @@ class ItemsController extends Controller
|
||||
{
|
||||
$item = Item::find($id);
|
||||
$item->name = $request->name;
|
||||
$item->unit = $request->unit;
|
||||
$item->unit_id = $request->unit_id;
|
||||
$item->description = $request->description;
|
||||
$item->price = $request->price;
|
||||
$item->save();
|
||||
@ -145,7 +148,7 @@ class ItemsController extends Controller
|
||||
$items = [];
|
||||
foreach ($request->id as $id) {
|
||||
$item = Item::deleteItem($id);
|
||||
if (!$item) {
|
||||
if ($item) {
|
||||
array_push($items, $id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,7 +46,9 @@ class OnboardingController extends Controller
|
||||
$languages = [
|
||||
["code"=>"en", "name" => "English"],
|
||||
["code"=>"fr", "name" => "French"],
|
||||
["code"=>"es", "name" => "Spanish"]
|
||||
["code"=>"es", "name" => "Spanish"],
|
||||
["code"=>"ar", "name" => "العربية"],
|
||||
["code"=>"de", "name" => "German"]
|
||||
];
|
||||
$fiscal_years = [
|
||||
['key' => 'january-december' , 'value' => '1-12'],
|
||||
@ -304,6 +306,10 @@ class OnboardingController extends Controller
|
||||
|
||||
Artisan::call('passport:install --force');
|
||||
|
||||
Artisan::call('db:seed', ['--class' => 'PaymentMethodSeeder', '--force' => true]);
|
||||
|
||||
Artisan::call('db:seed', ['--class' => 'UnitSeeder', '--force' => true]);
|
||||
|
||||
$client = DB::table('oauth_clients')->find(2);
|
||||
|
||||
$path = base_path('.env');
|
||||
|
||||
@ -4,13 +4,16 @@ namespace Crater\Http\Controllers;
|
||||
use Illuminate\Http\Request;
|
||||
use Crater\CompanySetting;
|
||||
use Crater\Currency;
|
||||
use Crater\Company;
|
||||
use Crater\Invoice;
|
||||
use Crater\Payment;
|
||||
use Crater\PaymentMethod;
|
||||
use Carbon\Carbon;
|
||||
use function MongoDB\BSON\toJSON;
|
||||
use Crater\User;
|
||||
use Crater\Http\Requests\PaymentRequest;
|
||||
use Validator;
|
||||
use Crater\Mail\PaymentPdf;
|
||||
|
||||
class PaymentController extends Controller
|
||||
{
|
||||
@ -23,19 +26,20 @@ class PaymentController extends Controller
|
||||
{
|
||||
$limit = $request->has('limit') ? $request->limit : 10;
|
||||
|
||||
$payments = Payment::with('user', 'invoice')
|
||||
$payments = Payment::with(['user', 'invoice', 'paymentMethod'])
|
||||
->join('users', 'users.id', '=', 'payments.user_id')
|
||||
->leftJoin('invoices', 'invoices.id', '=', 'payments.invoice_id')
|
||||
->leftJoin('payment_methods', 'payment_methods.id', '=', 'payments.payment_method_id')
|
||||
->applyFilters($request->only([
|
||||
'search',
|
||||
'payment_number',
|
||||
'payment_mode',
|
||||
'payment_method_id',
|
||||
'customer_id',
|
||||
'orderByField',
|
||||
'orderBy'
|
||||
]))
|
||||
->whereCompany($request->header('company'))
|
||||
->select('payments.*', 'users.name', 'invoices.invoice_number')
|
||||
->select('payments.*', 'users.name', 'invoices.invoice_number', 'payment_methods.name as payment_mode')
|
||||
->latest()
|
||||
->paginate($limit);
|
||||
|
||||
@ -66,6 +70,9 @@ class PaymentController extends Controller
|
||||
'customers' => User::where('role', 'customer')
|
||||
->whereCompany($request->header('company'))
|
||||
->get(),
|
||||
'paymentMethods' => PaymentMethod::whereCompany($request->header('company'))
|
||||
->latest()
|
||||
->get(),
|
||||
'nextPaymentNumberAttribute' => $nextPaymentNumberAttribute,
|
||||
'nextPaymentNumber' => $payment_prefix.'-'.$nextPaymentNumber,
|
||||
'payment_prefix' => $payment_prefix
|
||||
@ -113,13 +120,15 @@ class PaymentController extends Controller
|
||||
'user_id' => $request->user_id,
|
||||
'company_id' => $request->header('company'),
|
||||
'invoice_id' => $request->invoice_id,
|
||||
'payment_mode' => $request->payment_mode,
|
||||
'payment_method_id' => $request->payment_method_id,
|
||||
'amount' => $request->amount,
|
||||
'notes' => $request->notes,
|
||||
'unique_hash' => str_random(60)
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'payment' => $payment,
|
||||
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash),
|
||||
'success' => true
|
||||
]);
|
||||
}
|
||||
@ -132,7 +141,12 @@ class PaymentController extends Controller
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
//
|
||||
$payment = Payment::with(['user', 'invoice', 'paymentMethod'])->find($id);
|
||||
|
||||
return response()->json([
|
||||
'payment' => $payment,
|
||||
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -143,7 +157,7 @@ class PaymentController extends Controller
|
||||
*/
|
||||
public function edit(Request $request, $id)
|
||||
{
|
||||
$payment = Payment::with('user', 'invoice')->find($id);
|
||||
$payment = Payment::with(['user', 'invoice', 'paymentMethod'])->find($id);
|
||||
|
||||
$invoices = Invoice::where('paid_status', '<>', Invoice::STATUS_PAID)
|
||||
->where('user_id', $payment->user_id)->where('due_amount', '>', 0)
|
||||
@ -154,8 +168,12 @@ class PaymentController extends Controller
|
||||
'customers' => User::where('role', 'customer')
|
||||
->whereCompany($request->header('company'))
|
||||
->get(),
|
||||
'paymentMethods' => PaymentMethod::whereCompany($request->header('company'))
|
||||
->latest()
|
||||
->get(),
|
||||
'nextPaymentNumber' => $payment->getPaymentNumAttribute(),
|
||||
'payment_prefix' => $payment->getPaymentPrefixAttribute(),
|
||||
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash),
|
||||
'payment' => $payment,
|
||||
'invoices' => $invoices
|
||||
]);
|
||||
@ -208,13 +226,14 @@ class PaymentController extends Controller
|
||||
$payment->payment_number = $number_attributes['payment_number'];
|
||||
$payment->user_id = $request->user_id;
|
||||
$payment->invoice_id = $request->invoice_id;
|
||||
$payment->payment_mode = $request->payment_mode;
|
||||
$payment->payment_method_id = $request->payment_method_id;
|
||||
$payment->amount = $request->amount;
|
||||
$payment->notes = $request->notes;
|
||||
$payment->save();
|
||||
|
||||
return response()->json([
|
||||
'payment' => $payment,
|
||||
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash),
|
||||
'success' => true
|
||||
]);
|
||||
}
|
||||
@ -276,4 +295,37 @@ class PaymentController extends Controller
|
||||
'success' => true
|
||||
]);
|
||||
}
|
||||
|
||||
public function sendPayment(Request $request)
|
||||
{
|
||||
$payment = Payment::findOrFail($request->id);
|
||||
|
||||
$data['payment'] = $payment->toArray();
|
||||
$userId = $data['payment']['user_id'];
|
||||
$data['user'] = User::find($userId)->toArray();
|
||||
$data['company'] = Company::find($payment->company_id);
|
||||
$email = $data['user']['email'];
|
||||
$notificationEmail = CompanySetting::getSetting(
|
||||
'notification_email',
|
||||
$request->header('company')
|
||||
);
|
||||
|
||||
if (!$email) {
|
||||
return response()->json([
|
||||
'error' => 'user_email_does_not_exist'
|
||||
]);
|
||||
}
|
||||
|
||||
if (!$notificationEmail) {
|
||||
return response()->json([
|
||||
'error' => 'notification_email_does_not_exist'
|
||||
]);
|
||||
}
|
||||
|
||||
\Mail::to($email)->send(new PaymentPdf($data, $notificationEmail));
|
||||
|
||||
return response()->json([
|
||||
'success' => true
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
119
app/Http/Controllers/PaymentMethodController.php
Normal file
119
app/Http/Controllers/PaymentMethodController.php
Normal file
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Http\Controllers;
|
||||
|
||||
use Crater\PaymentMethod;
|
||||
use Illuminate\Http\Request;
|
||||
use Crater\Http\Requests\PaymentMethodRequest;
|
||||
|
||||
class PaymentMethodController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$paymentMethods = PaymentMethod::whereCompany($request->header('company'))
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'paymentMethods' => $paymentMethods
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(PaymentMethodRequest $request)
|
||||
{
|
||||
$paymentMethod = new PaymentMethod;
|
||||
$paymentMethod->name = $request->name;
|
||||
$paymentMethod->company_id = $request->header('company');
|
||||
$paymentMethod->save();
|
||||
|
||||
return response()->json([
|
||||
'paymentMethod' => $paymentMethod
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Crater\PaymentMethod $paymentMethod
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(PaymentMethod $paymentMethod)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \Crater\PaymentMethod $paymentMethod
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(PaymentMethod $paymentMethod)
|
||||
{
|
||||
return response()->json([
|
||||
'paymentMethod' => $paymentMethod
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Crater\PaymentMethod $paymentMethod
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(PaymentMethodRequest $request, PaymentMethod $paymentMethod)
|
||||
{
|
||||
$paymentMethod->name = $request->name;
|
||||
$paymentMethod->company_id = $request->header('company');
|
||||
$paymentMethod->save();
|
||||
|
||||
return response()->json([
|
||||
'paymentMethod' => $paymentMethod
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \Crater\PaymentMethod $paymentMethod
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(PaymentMethod $paymentMethod)
|
||||
{
|
||||
$payments = $paymentMethod->payments;
|
||||
|
||||
if ($payments->count() > 0) {
|
||||
return response()->json([
|
||||
'error' => 'payments_attached'
|
||||
]);
|
||||
}
|
||||
|
||||
$paymentMethod->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => 'Payment method deleted successfully'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,8 @@ namespace Crater\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Crater\Setting;
|
||||
use Crater\Mail\TestMail;
|
||||
use Mail;
|
||||
|
||||
class SettingsController extends Controller
|
||||
{
|
||||
@ -23,4 +25,18 @@ class SettingsController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function testEmailConfig(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'to' => 'required|email',
|
||||
'subject' => 'required',
|
||||
'message' => 'required'
|
||||
]);
|
||||
|
||||
Mail::to($request->to)->send(new TestMail($request->subject, $request->message));
|
||||
|
||||
return response()->json([
|
||||
'success' => true
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
119
app/Http/Controllers/UnitController.php
Normal file
119
app/Http/Controllers/UnitController.php
Normal file
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Http\Controllers;
|
||||
|
||||
use Crater\Unit;
|
||||
use Illuminate\Http\Request;
|
||||
use Crater\Http\Requests\UnitRequest;
|
||||
|
||||
class UnitController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$units = Unit::whereCompany($request->header('company'))
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'units' => $units
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(UnitRequest $request)
|
||||
{
|
||||
$unit = new Unit;
|
||||
$unit->name = $request->name;
|
||||
$unit->company_id = $request->header('company');
|
||||
$unit->save();
|
||||
|
||||
return response()->json([
|
||||
'unit' => $unit
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Crater\Unit $unit
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Unit $unit)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \Crater\Unit $unit
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(Unit $unit)
|
||||
{
|
||||
return response()->json([
|
||||
'unit' => $unit
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Crater\Unit $unit
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UnitRequest $request, Unit $unit)
|
||||
{
|
||||
$unit->name = $request->name;
|
||||
$unit->company_id = $request->header('company');
|
||||
$unit->save();
|
||||
|
||||
return response()->json([
|
||||
'unit' => $unit
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \Crater\Unit $unit
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Unit $unit)
|
||||
{
|
||||
$items = $unit->items;
|
||||
|
||||
if ($items->count() > 0) {
|
||||
return response()->json([
|
||||
'error' => 'items_attached'
|
||||
]);
|
||||
}
|
||||
|
||||
$unit->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => 'Unit deleted successfully'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,8 @@ use Crater\User;
|
||||
use Crater\Currency;
|
||||
use Crater\Setting;
|
||||
use Crater\Item;
|
||||
use Crater\PaymentMethod;
|
||||
use Crater\Unit;
|
||||
use Crater\TaxType;
|
||||
use DB;
|
||||
use Carbon\Carbon;
|
||||
@ -46,10 +48,18 @@ class UsersController extends Controller
|
||||
$request->header('company')
|
||||
);
|
||||
|
||||
$items = Item::all();
|
||||
$items = Item::with('taxes')->get();
|
||||
|
||||
$taxTypes = TaxType::latest()->get();
|
||||
|
||||
$paymentMethods = PaymentMethod::whereCompany($request->header('company'))
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
$units = Unit::whereCompany($request->header('company'))
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'user' => $user,
|
||||
'customers' => $customers,
|
||||
@ -61,6 +71,8 @@ class UsersController extends Controller
|
||||
'items' => $items,
|
||||
'taxTypes' => $taxTypes,
|
||||
'moment_date_format' => $moment_date_format,
|
||||
'paymentMethods' => $paymentMethods,
|
||||
'units' => $units,
|
||||
'fiscal_year' => $fiscal_year,
|
||||
]);
|
||||
}
|
||||
|
||||
40
app/Http/Requests/PaymentMethodRequest.php
Normal file
40
app/Http/Requests/PaymentMethodRequest.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class PaymentMethodRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$data = [
|
||||
'name' => 'required|unique:payment_methods,name'
|
||||
];
|
||||
|
||||
if ($this->getMethod() == 'PUT') {
|
||||
$data['name'] = [
|
||||
'required',
|
||||
Rule::unique('payment_methods')->ignore($this->route('payment_method'), 'id')
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
40
app/Http/Requests/UnitRequest.php
Normal file
40
app/Http/Requests/UnitRequest.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class UnitRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$data = [
|
||||
'name' => 'required|unique:units,name'
|
||||
];
|
||||
|
||||
if ($this->getMethod() == 'PUT') {
|
||||
$data['name'] = [
|
||||
'required',
|
||||
Rule::unique('units')->ignore($this->route('unit'), 'id')
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
19
app/Item.php
19
app/Item.php
@ -24,19 +24,24 @@ class Item extends Model
|
||||
'formattedCreatedAt'
|
||||
];
|
||||
|
||||
public function unit()
|
||||
{
|
||||
return $this->belongsTo(Unit::class);
|
||||
}
|
||||
|
||||
public function scopeWhereSearch($query, $search)
|
||||
{
|
||||
return $query->where('name', 'LIKE', '%'.$search.'%');
|
||||
return $query->where('items.name', 'LIKE', '%'.$search.'%');
|
||||
}
|
||||
|
||||
public function scopeWherePrice($query, $price)
|
||||
{
|
||||
return $query->where('price', $price);
|
||||
return $query->where('items.price', $price);
|
||||
}
|
||||
|
||||
public function scopeWhereUnit($query, $unit)
|
||||
public function scopeWhereUnit($query, $unit_id)
|
||||
{
|
||||
return $query->where('unit', $unit);
|
||||
return $query->where('items.unit_id', $unit_id);
|
||||
}
|
||||
|
||||
public function scopeWhereOrder($query, $orderByField, $orderBy)
|
||||
@ -56,8 +61,8 @@ class Item extends Model
|
||||
$query->wherePrice($filters->get('price'));
|
||||
}
|
||||
|
||||
if ($filters->get('unit')) {
|
||||
$query->whereUnit($filters->get('unit'));
|
||||
if ($filters->get('unit_id')) {
|
||||
$query->whereUnit($filters->get('unit_id'));
|
||||
}
|
||||
|
||||
if ($filters->get('orderByField') || $filters->get('orderBy')) {
|
||||
@ -80,7 +85,7 @@ class Item extends Model
|
||||
|
||||
public function scopeWhereCompany($query, $company_id)
|
||||
{
|
||||
$query->where('company_id', $company_id);
|
||||
$query->where('items.company_id', $company_id);
|
||||
}
|
||||
|
||||
public function invoiceItems()
|
||||
|
||||
162
app/Listeners/Updates/v2/Version220.php
Normal file
162
app/Listeners/Updates/v2/Version220.php
Normal file
@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Listeners\Updates\v2;
|
||||
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Crater\Setting;
|
||||
use Crater\Unit;
|
||||
use Crater\PaymentMethod;
|
||||
use Crater\Currency;
|
||||
use Crater\Payment;
|
||||
use Crater\Item;
|
||||
use Crater\User;
|
||||
use Crater\Listeners\Updates\Listener;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class Version220 extends Listener
|
||||
{
|
||||
const VERSION = '2.2.0';
|
||||
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param object $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle($event)
|
||||
{
|
||||
if ($this->isListenerFired($event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->changeMigrations();
|
||||
|
||||
$this->addSeederData();
|
||||
|
||||
$this->databaseChanges();
|
||||
|
||||
$this->changeMigrations(true);
|
||||
|
||||
Setting::setSetting('version', static::VERSION);
|
||||
}
|
||||
|
||||
public function changeMigrations($removeColumn = false)
|
||||
{
|
||||
if ($removeColumn) {
|
||||
\Schema::table('items', function (Blueprint $table) {
|
||||
$table->dropColumn('unit');
|
||||
});
|
||||
|
||||
\Schema::table('payments', function (Blueprint $table) {
|
||||
$table->dropColumn('payment_mode');
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
\Schema::create('units', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->integer('company_id')->unsigned()->nullable();
|
||||
$table->foreign('company_id')->references('id')->on('companies');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
\Schema::table('items', function (Blueprint $table) {
|
||||
$table->integer('unit_id')->unsigned()->nullable();
|
||||
$table->foreign('unit_id')->references('id')->on('units')->onDelete('cascade');
|
||||
});
|
||||
|
||||
\Schema::create('payment_methods', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->integer('company_id')->unsigned()->nullable();
|
||||
$table->foreign('company_id')->references('id')->on('companies');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
\Schema::table('payments', function (Blueprint $table) {
|
||||
$table->string('unique_hash')->nullable();
|
||||
$table->integer('payment_method_id')->unsigned()->nullable();
|
||||
$table->foreign('payment_method_id')->references('id')->on('payment_methods')->onDelete('cascade');
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function addSeederData()
|
||||
{
|
||||
$company_id = User::where('role', 'admin')->first()->company_id;
|
||||
|
||||
Unit::create(['name' => 'box', 'company_id' => $company_id]);
|
||||
Unit::create(['name' => 'cm', 'company_id' => $company_id]);
|
||||
Unit::create(['name' => 'dz', 'company_id' => $company_id]);
|
||||
Unit::create(['name' => 'ft', 'company_id' => $company_id]);
|
||||
Unit::create(['name' => 'g', 'company_id' => $company_id]);
|
||||
Unit::create(['name' => 'in', 'company_id' => $company_id]);
|
||||
Unit::create(['name' => 'kg', 'company_id' => $company_id]);
|
||||
Unit::create(['name' => 'km', 'company_id' => $company_id]);
|
||||
Unit::create(['name' => 'lb', 'company_id' => $company_id]);
|
||||
Unit::create(['name' => 'mg', 'company_id' => $company_id]);
|
||||
Unit::create(['name' => 'pc', 'company_id' => $company_id]);
|
||||
|
||||
PaymentMethod::create(['name' => 'Cash', 'company_id' => $company_id]);
|
||||
PaymentMethod::create(['name' => 'Check', 'company_id' => $company_id]);
|
||||
PaymentMethod::create(['name' => 'Credit Card', 'company_id' => $company_id]);
|
||||
PaymentMethod::create(['name' => 'Bank Transfer', 'company_id' => $company_id]);
|
||||
|
||||
Currency::create([
|
||||
'name' => 'Serbian Dinar',
|
||||
'code' => 'RSD',
|
||||
'symbol' => 'RSD',
|
||||
'precision' => '2',
|
||||
'thousand_separator' => '.',
|
||||
'decimal_separator' => ','
|
||||
]);
|
||||
}
|
||||
|
||||
public function databaseChanges()
|
||||
{
|
||||
$payments = Payment::all();
|
||||
|
||||
if ($payments) {
|
||||
foreach ($payments as $payment) {
|
||||
$payment->unique_hash = str_random(60);
|
||||
$payment->save();
|
||||
|
||||
$paymentMethod = PaymentMethod::where('name', $payment->payment_mode)
|
||||
->first();
|
||||
|
||||
if ($paymentMethod) {
|
||||
$payment->payment_method_id = $paymentMethod->id;
|
||||
$payment->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$items = Item::all();
|
||||
|
||||
if ($items) {
|
||||
foreach ($items as $item) {
|
||||
$unit = Unit::where('name', $item->unit)
|
||||
->first();
|
||||
|
||||
if ($unit) {
|
||||
$item->unit_id = $unit->id;
|
||||
$item->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
38
app/Mail/PaymentPdf.php
Normal file
38
app/Mail/PaymentPdf.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class PaymentPdf extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public $data = [];
|
||||
|
||||
public $notificationEmail = '';
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($data, $notificationEmail)
|
||||
{
|
||||
$this->data = $data;
|
||||
$this->notificationEmail = $notificationEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->from($this->notificationEmail)->markdown('emails.send.payment', ['data', $this->data]);
|
||||
}
|
||||
}
|
||||
38
app/Mail/TestMail.php
Normal file
38
app/Mail/TestMail.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
namespace Crater\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
||||
class TestMail extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
public $subject;
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param $subject
|
||||
* @param $message
|
||||
*/
|
||||
public function __construct($subject, $message)
|
||||
{
|
||||
$this->subject = $subject;
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->subject($this->subject)->markdown('emails.test')->with([
|
||||
'my_message' => $this->message
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ use Crater\User;
|
||||
use Crater\Invoice;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Crater\PaymentMethod;
|
||||
|
||||
class Payment extends Model
|
||||
{
|
||||
@ -19,9 +20,11 @@ class Payment extends Model
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'invoice_id',
|
||||
'payment_method_id',
|
||||
'payment_date',
|
||||
'company_id',
|
||||
'notes',
|
||||
'unique_hash',
|
||||
'payment_number',
|
||||
'payment_mode',
|
||||
'amount'
|
||||
@ -84,7 +87,6 @@ class Payment extends Model
|
||||
return $prefix;
|
||||
}
|
||||
|
||||
|
||||
public function invoice()
|
||||
{
|
||||
return $this->belongsTo(Invoice::class);
|
||||
@ -95,6 +97,11 @@ class Payment extends Model
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function paymentMethod()
|
||||
{
|
||||
return $this->belongsTo(PaymentMethod::class);
|
||||
}
|
||||
|
||||
public function getFormattedCreatedAtAttribute($value)
|
||||
{
|
||||
$dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id);
|
||||
@ -123,9 +130,9 @@ class Payment extends Model
|
||||
return $query->where('payments.payment_number', 'LIKE', '%'.$paymentNumber.'%');
|
||||
}
|
||||
|
||||
public function scopePaymentMode($query, $paymentMode)
|
||||
public function scopePaymentMethod($query, $paymentMethodId)
|
||||
{
|
||||
return $query->where('payments.payment_mode', $paymentMode);
|
||||
return $query->where('payments.payment_method_id', $paymentMethodId);
|
||||
}
|
||||
|
||||
public function scopeApplyFilters($query, array $filters)
|
||||
@ -140,8 +147,8 @@ class Payment extends Model
|
||||
$query->paymentNumber($filters->get('payment_number'));
|
||||
}
|
||||
|
||||
if ($filters->get('payment_mode')) {
|
||||
$query->paymentMode($filters->get('payment_mode'));
|
||||
if ($filters->get('payment_method_id')) {
|
||||
$query->paymentMethod($filters->get('payment_method_id'));
|
||||
}
|
||||
|
||||
if ($filters->get('customer_id')) {
|
||||
|
||||
25
app/PaymentMethod.php
Normal file
25
app/PaymentMethod.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Crater;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class PaymentMethod extends Model
|
||||
{
|
||||
protected $fillable = ['name', 'company_id'];
|
||||
|
||||
public function payments()
|
||||
{
|
||||
return $this->hasMany(Payment::class);
|
||||
}
|
||||
|
||||
public function company()
|
||||
{
|
||||
return $this->belongsTo(Company::class);
|
||||
}
|
||||
|
||||
public function scopeWhereCompany($query, $company_id)
|
||||
{
|
||||
$query->where('company_id', $company_id);
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ use Crater\Listeners\Updates\v2\Version200;
|
||||
use Crater\Listeners\Updates\v2\Version201;
|
||||
use Crater\Listeners\Updates\v2\Version202;
|
||||
use Crater\Listeners\Updates\v2\Version210;
|
||||
use Crater\Listeners\Updates\v2\Version220;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
@ -25,6 +26,7 @@ class EventServiceProvider extends ServiceProvider
|
||||
Version201::class,
|
||||
Version202::class,
|
||||
Version210::class,
|
||||
Version220::class,
|
||||
],
|
||||
Registered::class => [
|
||||
SendEmailVerificationNotification::class,
|
||||
|
||||
26
app/Unit.php
Normal file
26
app/Unit.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Crater;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Crater\Item;
|
||||
|
||||
class Unit extends Model
|
||||
{
|
||||
protected $fillable = ['name', 'company_id'];
|
||||
|
||||
public function items()
|
||||
{
|
||||
return $this->hasMany(Item::class);
|
||||
}
|
||||
|
||||
public function company()
|
||||
{
|
||||
return $this->belongsTo(Company::class);
|
||||
}
|
||||
|
||||
public function scopeWhereCompany($query, $company_id)
|
||||
{
|
||||
$query->where('company_id', $company_id);
|
||||
}
|
||||
}
|
||||
34
database/migrations/2017_04_11_064308_create_units_table.php
Normal file
34
database/migrations/2017_04_11_064308_create_units_table.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateUnitsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('units', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->integer('company_id')->unsigned()->nullable();
|
||||
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('units');
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,8 @@ class CreateItemsTable extends Migration
|
||||
$table->unsignedBigInteger('price');
|
||||
$table->integer('company_id')->unsigned()->nullable();
|
||||
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
||||
$table->integer('unit_id')->unsigned()->nullable();
|
||||
$table->foreign('unit_id')->references('id')->on('units')->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
@ -30,6 +30,6 @@ class CreateExpenseCategoriesTable extends Migration
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('expenses_categories');
|
||||
Schema::dropIfExists('expense_categories');
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,6 +39,6 @@ class CreateAddressesTable extends Migration
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('address');
|
||||
Schema::dropIfExists('addresses');
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreatePaymentMethodsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('payment_methods', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->integer('company_id')->unsigned()->nullable();
|
||||
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('payment_methods');
|
||||
}
|
||||
}
|
||||
@ -16,16 +16,18 @@ class CreatePaymentsTable extends Migration
|
||||
Schema::create('payments', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('payment_number');
|
||||
$table->string('payment_mode')->nullable();
|
||||
$table->date('payment_date');
|
||||
$table->text('notes')->nullable();
|
||||
$table->unsignedBigInteger('amount');
|
||||
$table->string('unique_hash')->nullable();
|
||||
$table->integer('user_id')->unsigned();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->integer('invoice_id')->unsigned()->nullable();
|
||||
$table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
|
||||
$table->integer('company_id')->unsigned()->nullable();
|
||||
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
||||
$table->integer('payment_method_id')->unsigned()->nullable();
|
||||
$table->foreign('payment_method_id')->references('id')->on('payment_methods')->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
20
database/seeds/PaymentMethodSeeder.php
Normal file
20
database/seeds/PaymentMethodSeeder.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Crater\PaymentMethod;
|
||||
|
||||
class PaymentMethodSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
PaymentMethod::create(['name' => 'Cash', 'company_id' => 1]);
|
||||
PaymentMethod::create(['name' => 'Check', 'company_id' => 1]);
|
||||
PaymentMethod::create(['name' => 'Credit Card', 'company_id' => 1]);
|
||||
PaymentMethod::create(['name' => 'Bank Transfer', 'company_id' => 1]);
|
||||
}
|
||||
}
|
||||
27
database/seeds/UnitSeeder.php
Normal file
27
database/seeds/UnitSeeder.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Crater\Unit;
|
||||
|
||||
class UnitSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
Unit::create(['name' => 'box', 'company_id' => 1]);
|
||||
Unit::create(['name' => 'cm', 'company_id' => 1]);
|
||||
Unit::create(['name' => 'dz', 'company_id' => 1]);
|
||||
Unit::create(['name' => 'ft', 'company_id' => 1]);
|
||||
Unit::create(['name' => 'g', 'company_id' => 1]);
|
||||
Unit::create(['name' => 'in', 'company_id' => 1]);
|
||||
Unit::create(['name' => 'kg', 'company_id' => 1]);
|
||||
Unit::create(['name' => 'km', 'company_id' => 1]);
|
||||
Unit::create(['name' => 'lb', 'company_id' => 1]);
|
||||
Unit::create(['name' => 'mg', 'company_id' => 1]);
|
||||
Unit::create(['name' => 'pc', 'company_id' => 1]);
|
||||
}
|
||||
}
|
||||
@ -48,6 +48,7 @@
|
||||
"toastr": "^2.1.4",
|
||||
"upgrade": "^1.1.0",
|
||||
"v-money": "^0.8.1",
|
||||
"v-tooltip": "^2.0.2",
|
||||
"vue": "^2.5.17",
|
||||
"vue-avatar-cropper": "^1.0.5",
|
||||
"vue-i18n": "^8.14.0",
|
||||
|
||||
2
public/assets/css/crater.css
vendored
2
public/assets/css/crater.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,4 +1,4 @@
|
||||
{
|
||||
"/assets/js/app.js": "/assets/js/app.js?id=a9f802b3fe774e87bf0c",
|
||||
"/assets/css/crater.css": "/assets/css/crater.css?id=193e5770a0e7a8604f35"
|
||||
"/assets/js/app.js": "/assets/js/app.js?id=5ab8427ce5098da40a94",
|
||||
"/assets/css/crater.css": "/assets/css/crater.css?id=e6b0dadafbe07316a9ce"
|
||||
}
|
||||
|
||||
2
resources/assets/js/bootstrap.js
vendored
2
resources/assets/js/bootstrap.js
vendored
@ -12,6 +12,7 @@ import CustomerModal from './components/base/modal/CustomerModal.vue'
|
||||
import TaxTypeModal from './components/base/modal/TaxTypeModal.vue'
|
||||
import CategoryModal from './components/base/modal/CategoryModal.vue'
|
||||
import money from 'v-money'
|
||||
import VTooltip from 'v-tooltip'
|
||||
|
||||
/**
|
||||
* Global css plugins
|
||||
@ -107,6 +108,7 @@ window.toastr = require('toastr')
|
||||
|
||||
Vue.use(VueRouter)
|
||||
Vue.use(Vuex)
|
||||
Vue.use(VTooltip)
|
||||
|
||||
// register directive v-money and component <money>
|
||||
Vue.use(money, {precision: 2})
|
||||
|
||||
@ -21,6 +21,9 @@ import EstimateTemplate from './EstimateTemplate'
|
||||
import InvoiceTemplate from './InvoiceTemplate'
|
||||
import CustomerModal from './CustomerModal'
|
||||
import CategoryModal from './CategoryModal'
|
||||
import PaymentMode from './PaymentModeModal'
|
||||
import ItemUnit from './ItemUnitModal'
|
||||
import MailTestModal from './MailTestModal'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -29,7 +32,10 @@ export default {
|
||||
EstimateTemplate,
|
||||
InvoiceTemplate,
|
||||
CustomerModal,
|
||||
CategoryModal
|
||||
CategoryModal,
|
||||
PaymentMode,
|
||||
ItemUnit,
|
||||
MailTestModal
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
||||
@ -341,6 +341,7 @@ export default {
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
return {
|
||||
isEdit: false,
|
||||
isLoading: false,
|
||||
countryList: [],
|
||||
billingCountry: null,
|
||||
@ -399,9 +400,22 @@ export default {
|
||||
...mapGetters('currency', [
|
||||
'defaultCurrency',
|
||||
'currencies'
|
||||
]),
|
||||
...mapGetters('modal', [
|
||||
'modalDataID',
|
||||
'modalData',
|
||||
'modalActive'
|
||||
])
|
||||
},
|
||||
watch: {
|
||||
'modalDataID' (val) {
|
||||
if (val) {
|
||||
this.isEdit = true
|
||||
this.setData()
|
||||
} else {
|
||||
this.isEdit = false
|
||||
}
|
||||
},
|
||||
billingCountry () {
|
||||
if (this.billingCountry) {
|
||||
this.billing.country_id = this.billingCountry.id
|
||||
@ -419,6 +433,9 @@ export default {
|
||||
this.$refs.name.focus = true
|
||||
this.currency = this.defaultCurrency
|
||||
this.fetchCountry()
|
||||
if (this.modalDataID) {
|
||||
this.setData()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('invoice', {
|
||||
@ -493,6 +510,24 @@ export default {
|
||||
this.formData.addresses = [{...this.shipping, type: 'shipping'}]
|
||||
return true
|
||||
},
|
||||
async setData () {
|
||||
this.formData.id = this.modalData.id
|
||||
this.formData.name = this.modalData.name
|
||||
this.formData.email = this.modalData.email
|
||||
this.formData.contact_name = this.modalData.contact_name
|
||||
this.formData.phone = this.modalData.phone
|
||||
this.formData.website = this.modalData.website
|
||||
this.currency = this.modalData.currency
|
||||
|
||||
if (this.modalData.billing_address) {
|
||||
this.billing = this.modalData.billing_address
|
||||
this.billingCountry = this.modalData.billing_address.country
|
||||
}
|
||||
if (this.modalData.shipping_address) {
|
||||
this.shipping = this.modalData.shipping_address
|
||||
this.shippingCountry = this.modalData.shipping_address.country
|
||||
}
|
||||
},
|
||||
async submitCustomerData () {
|
||||
this.$v.formData.$touch()
|
||||
|
||||
@ -510,14 +545,23 @@ export default {
|
||||
this.formData.currency_id = this.defaultCurrency.id
|
||||
}
|
||||
try {
|
||||
let response = await this.addCustomer(this.formData)
|
||||
let response = null
|
||||
if (this.modalDataID) {
|
||||
response = await this.updateCustomer(this.formData)
|
||||
} else {
|
||||
response = await this.addCustomer(this.formData)
|
||||
}
|
||||
if (response.data) {
|
||||
window.toastr['success'](this.$tc('customers.created_message'))
|
||||
if (this.modalDataID) {
|
||||
window.toastr['success'](this.$tc('customers.updated_message'))
|
||||
} else {
|
||||
window.toastr['success'](this.$tc('customers.created_message'))
|
||||
}
|
||||
this.isLoading = false
|
||||
if (this.$route.name === 'invoices.create') {
|
||||
if (this.$route.name === 'invoices.create' || this.$route.name === 'invoices.edit') {
|
||||
this.setInvoiceCustomer(response.data.customer.id)
|
||||
}
|
||||
if (this.$route.name === 'estimates.create') {
|
||||
if (this.$route.name === 'estimates.create' || this.$route.name === 'estimates.edit') {
|
||||
this.setEstimateCustomer(response.data.customer.id)
|
||||
}
|
||||
this.resetData()
|
||||
|
||||
@ -45,14 +45,34 @@
|
||||
<div class="col-sm-7">
|
||||
<base-select
|
||||
v-model="formData.unit"
|
||||
:options="units"
|
||||
:options="itemUnits"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
label="name"
|
||||
>
|
||||
<div slot="afterList">
|
||||
<button type="button" class="list-add-button" @click="addItemUnit">
|
||||
<font-awesome-icon class="icon" icon="cart-plus" />
|
||||
<label>{{ $t('settings.customization.items.add_item_unit') }}</label>
|
||||
</button>
|
||||
</div>
|
||||
</base-select>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isTexPerItem" class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('items.taxes') }}</label>
|
||||
<div class="col-sm-7">
|
||||
<base-select
|
||||
v-model="formData.taxes"
|
||||
:options="getTaxTypes"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:allow-empty="true"
|
||||
:multiple="true"
|
||||
label="tax_name"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('items.description') }}</label>
|
||||
<div class="col-sm-7">
|
||||
@ -124,11 +144,13 @@ export default {
|
||||
{ name: 'mg', value: 'mg' },
|
||||
{ name: 'pc', value: 'pc' }
|
||||
],
|
||||
taxes: [],
|
||||
formData: {
|
||||
name: null,
|
||||
price: null,
|
||||
description: null,
|
||||
unit: null
|
||||
unit: null,
|
||||
taxes: []
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -161,12 +183,28 @@ export default {
|
||||
this.formData.price = newValue * 100
|
||||
}
|
||||
},
|
||||
// itemUnits () {
|
||||
// return this.units
|
||||
// },
|
||||
...mapGetters('modal', [
|
||||
'modalDataID'
|
||||
'modalDataID',
|
||||
'modalData'
|
||||
]),
|
||||
...mapGetters('item', [
|
||||
'getItemById'
|
||||
])
|
||||
'getItemById',
|
||||
'itemUnits'
|
||||
]),
|
||||
...mapGetters('taxType', [
|
||||
'taxTypes'
|
||||
]),
|
||||
isTexPerItem () {
|
||||
return this.modalData.taxPerItem === 'YES'
|
||||
},
|
||||
getTaxTypes () {
|
||||
return this.taxTypes.map(tax => {
|
||||
return {...tax, tax_name: tax.name + ' (' + tax.percent + '%)'}
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modalDataID () {
|
||||
@ -179,12 +217,17 @@ export default {
|
||||
this.isEdit = true
|
||||
this.fetchEditData()
|
||||
}
|
||||
|
||||
if (this.isEdit) {
|
||||
this.loadEditData()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$refs.name.focus = true
|
||||
},
|
||||
methods: {
|
||||
...mapActions('modal', [
|
||||
'openModal',
|
||||
'closeModal',
|
||||
'resetModalData'
|
||||
]),
|
||||
@ -203,7 +246,6 @@ export default {
|
||||
unit: null,
|
||||
id: null
|
||||
}
|
||||
|
||||
this.$v.$reset()
|
||||
},
|
||||
fetchEditData () {
|
||||
@ -230,9 +272,20 @@ export default {
|
||||
if (this.isEdit) {
|
||||
response = await this.updateItem(this.formData)
|
||||
} else {
|
||||
response = await this.addItem(this.formData)
|
||||
let data = {
|
||||
...this.formData,
|
||||
taxes: this.formData.taxes.map(tax => {
|
||||
return {
|
||||
tax_type_id: tax.id,
|
||||
amount: ((this.formData.price * tax.percent) / 100),
|
||||
percent: tax.percent,
|
||||
name: tax.name,
|
||||
collective_tax: 0
|
||||
}
|
||||
})
|
||||
}
|
||||
response = await this.addItem(data)
|
||||
}
|
||||
|
||||
if (response.data) {
|
||||
window.toastr['success'](this.$tc('items.created_message'))
|
||||
this.setItem(response.data.item)
|
||||
@ -245,6 +298,12 @@ export default {
|
||||
}
|
||||
window.toastr['error'](response.data.error)
|
||||
},
|
||||
async addItemUnit () {
|
||||
this.openModal({
|
||||
'title': 'Add Item Unit',
|
||||
'componentName': 'ItemUnit'
|
||||
})
|
||||
},
|
||||
closeItemModal () {
|
||||
this.resetFormData()
|
||||
this.closeModal()
|
||||
|
||||
148
resources/assets/js/components/base/modal/ItemUnitModal.vue
Normal file
148
resources/assets/js/components/base/modal/ItemUnitModal.vue
Normal file
@ -0,0 +1,148 @@
|
||||
<template>
|
||||
<div class="item-unit-modal">
|
||||
<form action="" @submit.prevent="submitItemUnit">
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('settings.customization.items.unit_name') }} <span class="required"> *</span></label>
|
||||
<div class="col-sm-7">
|
||||
<base-input
|
||||
ref="name"
|
||||
:invalid="$v.formData.name.$error"
|
||||
v-model="formData.name"
|
||||
type="text"
|
||||
@input="$v.formData.name.$touch()"
|
||||
/>
|
||||
<div v-if="$v.formData.name.$error">
|
||||
<span v-if="!$v.formData.name.required" class="form-group__message text-danger">{{ $tc('validation.required') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<base-button
|
||||
:outline="true"
|
||||
class="mr-3"
|
||||
color="theme"
|
||||
type="button"
|
||||
@click="closePaymentModeModal"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
:loading="isLoading"
|
||||
color="theme"
|
||||
icon="save"
|
||||
type="submit"
|
||||
>
|
||||
{{ !isEdit ? $t('general.save') : $t('general.update') }}
|
||||
</base-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, minLength } = require('vuelidate/lib/validators')
|
||||
export default {
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
return {
|
||||
isEdit: false,
|
||||
isLoading: false,
|
||||
formData: {
|
||||
id: null,
|
||||
name: null
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('modal', [
|
||||
'modalDataID',
|
||||
'modalData',
|
||||
'modalActive'
|
||||
])
|
||||
},
|
||||
validations: {
|
||||
formData: {
|
||||
name: {
|
||||
required,
|
||||
minLength: minLength(2)
|
||||
}
|
||||
}
|
||||
},
|
||||
async mounted () {
|
||||
this.$refs.name.focus = true
|
||||
if (this.modalDataID) {
|
||||
this.isEdit = true
|
||||
this.setData()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('modal', [
|
||||
'closeModal',
|
||||
'resetModalData'
|
||||
]),
|
||||
...mapActions('item', [
|
||||
'addItemUnit',
|
||||
'updateItemUnit',
|
||||
'fatchItemUnit'
|
||||
]),
|
||||
resetFormData () {
|
||||
this.formData = {
|
||||
id: null,
|
||||
name: null
|
||||
}
|
||||
this.$v.formData.$reset()
|
||||
},
|
||||
async submitItemUnit () {
|
||||
this.$v.formData.$touch()
|
||||
if (this.$v.$invalid) {
|
||||
return true
|
||||
}
|
||||
this.isLoading = true
|
||||
|
||||
let response
|
||||
|
||||
if (this.isEdit) {
|
||||
response = await this.updateItemUnit(this.formData)
|
||||
|
||||
if (response.data) {
|
||||
window.toastr['success'](this.$t('settings.customization.items.item_unit_updated'))
|
||||
this.closePaymentModeModal()
|
||||
return true
|
||||
}
|
||||
|
||||
window.toastr['error'](response.data.error)
|
||||
} else {
|
||||
try {
|
||||
response = await this.addItemUnit(this.formData)
|
||||
if (response.data) {
|
||||
this.isLoading = false
|
||||
window.toastr['success'](this.$t('settings.customization.items.item_unit_added'))
|
||||
this.closePaymentModeModal()
|
||||
return true
|
||||
} window.toastr['error'](response.data.error)
|
||||
} catch (err) {
|
||||
if (err.response.data.errors.name) {
|
||||
this.isLoading = true
|
||||
window.toastr['error'](this.$t('validation.item_unit_already_taken'))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async setData () {
|
||||
this.formData = {
|
||||
id: this.modalData.id,
|
||||
name: this.modalData.name
|
||||
}
|
||||
},
|
||||
closePaymentModeModal () {
|
||||
this.resetModalData()
|
||||
this.resetFormData()
|
||||
this.closeModal()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
166
resources/assets/js/components/base/modal/MailTestModal.vue
Normal file
166
resources/assets/js/components/base/modal/MailTestModal.vue
Normal file
@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<div class="mail-test-modal">
|
||||
<form action="" @submit.prevent="onTestMailSend">
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('general.to') }} <span class="required"> *</span></label>
|
||||
<div class="col-sm-7">
|
||||
<base-input
|
||||
ref="to"
|
||||
:invalid="$v.formData.to.$error"
|
||||
v-model="formData.to"
|
||||
type="text"
|
||||
@input="$v.formData.to.$touch()"
|
||||
/>
|
||||
<div v-if="$v.formData.to.$error">
|
||||
<span v-if="!$v.formData.to.required" class="form-group__message text-danger">{{ $tc('validation.required') }}</span>
|
||||
<span v-if="!$v.formData.to.email" class="form-group__message text-danger"> {{ $t('validation.email_incorrect') }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('general.subject') }} <span class="required"> *</span></label>
|
||||
<div class="col-sm-7">
|
||||
<div class="base-input">
|
||||
<base-input
|
||||
:invalid="$v.formData.subject.$error"
|
||||
v-model="formData.subject"
|
||||
type="text"
|
||||
@input="$v.formData.subject.$touch()"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="$v.formData.subject.$error">
|
||||
<span v-if="!$v.formData.subject.required" class="text-danger">{{ $t('validation.required') }}</span>
|
||||
<span v-if="!$v.formData.subject.maxLength" class="text-danger">{{ $t('validation.subject_maxlength') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('general.message') }}<span class="required"> *</span></label>
|
||||
<div class="col-sm-7">
|
||||
<base-text-area
|
||||
v-model="formData.message"
|
||||
:invalid="$v.formData.message.$error"
|
||||
rows="4"
|
||||
cols="50"
|
||||
@input="$v.formData.message.$touch()"
|
||||
/>
|
||||
<div v-if="$v.formData.message.$error">
|
||||
<span v-if="!$v.formData.message.required" class="text-danger">{{ $t('validation.required') }}</span>
|
||||
<span v-if="!$v.formData.message.maxLength" class="text-danger">{{ $t('validation.message_maxlength') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<base-button
|
||||
:outline="true"
|
||||
class="mr-3"
|
||||
color="theme"
|
||||
type="button"
|
||||
@click="closeTaxModal"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
:loading="isLoading"
|
||||
color="theme"
|
||||
icon="save"
|
||||
type="submit"
|
||||
>
|
||||
{{ !isEdit ? $t('general.save') : $t('general.update') }}
|
||||
</base-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, minLength, email, maxLength } = require('vuelidate/lib/validators')
|
||||
export default {
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
return {
|
||||
isEdit: false,
|
||||
isLoading: false,
|
||||
formData: {
|
||||
to: null,
|
||||
subject: null,
|
||||
message: null
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('modal', [
|
||||
'modalDataID',
|
||||
'modalData',
|
||||
'modalActive'
|
||||
])
|
||||
},
|
||||
validations: {
|
||||
formData: {
|
||||
to: {
|
||||
required,
|
||||
email
|
||||
},
|
||||
subject: {
|
||||
required,
|
||||
maxLength: maxLength(100)
|
||||
},
|
||||
message: {
|
||||
required,
|
||||
maxLength: maxLength(255)
|
||||
}
|
||||
}
|
||||
},
|
||||
async mounted () {
|
||||
this.$refs.to.focus = true
|
||||
},
|
||||
methods: {
|
||||
...mapActions('modal', [
|
||||
'closeModal',
|
||||
'resetModalData'
|
||||
]),
|
||||
resetFormData () {
|
||||
this.formData = {
|
||||
to: null,
|
||||
subject: null,
|
||||
message: null
|
||||
}
|
||||
this.$v.formData.$reset()
|
||||
},
|
||||
async onTestMailSend () {
|
||||
this.$v.formData.$touch()
|
||||
|
||||
if (this.$v.$invalid) {
|
||||
return true
|
||||
}
|
||||
|
||||
this.isLoading = true
|
||||
let response = await axios.post('/api/settings/test/mail', this.formData)
|
||||
if (response.data) {
|
||||
|
||||
if (response.data.success) {
|
||||
window.toastr['success'](this.$tc('general.send_mail_successfully'))
|
||||
this.closeTaxModal()
|
||||
this.isLoading = false
|
||||
return true
|
||||
}
|
||||
|
||||
window.toastr['error'](this.$tc('validation.something_went_wrong'))
|
||||
this.closeTaxModal()
|
||||
this.isLoading = false
|
||||
return true
|
||||
}
|
||||
window.toastr['error'](response.data.error)
|
||||
},
|
||||
closeTaxModal () {
|
||||
this.resetModalData()
|
||||
this.resetFormData()
|
||||
this.closeModal()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
143
resources/assets/js/components/base/modal/PaymentModeModal.vue
Normal file
143
resources/assets/js/components/base/modal/PaymentModeModal.vue
Normal file
@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<div class="payment-modes-modal">
|
||||
<form action="" @submit.prevent="submitPaymentMode">
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label input-label">{{ $t('settings.customization.payments.mode_name') }} <span class="required"> *</span></label>
|
||||
<div class="col-sm-7">
|
||||
<base-input
|
||||
ref="name"
|
||||
:invalid="$v.formData.name.$error"
|
||||
v-model="formData.name"
|
||||
type="text"
|
||||
@input="$v.formData.name.$touch()"
|
||||
/>
|
||||
<div v-if="$v.formData.name.$error">
|
||||
<span v-if="!$v.formData.name.required" class="form-group__message text-danger">{{ $tc('validation.required') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<base-button
|
||||
:outline="true"
|
||||
class="mr-3"
|
||||
color="theme"
|
||||
type="button"
|
||||
@click="closePaymentModeModal"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</base-button>
|
||||
<base-button
|
||||
:loading="isLoading"
|
||||
color="theme"
|
||||
icon="save"
|
||||
type="submit"
|
||||
>
|
||||
{{ !isEdit ? $t('general.save') : $t('general.update') }}
|
||||
</base-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
import { validationMixin } from 'vuelidate'
|
||||
const { required, minLength } = require('vuelidate/lib/validators')
|
||||
|
||||
export default {
|
||||
mixins: [validationMixin],
|
||||
data () {
|
||||
return {
|
||||
isEdit: false,
|
||||
isLoading: false,
|
||||
formData: {
|
||||
id: null,
|
||||
name: null
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('modal', [
|
||||
'modalDataID',
|
||||
'modalData',
|
||||
'modalActive'
|
||||
])
|
||||
},
|
||||
validations: {
|
||||
formData: {
|
||||
name: {
|
||||
required,
|
||||
minLength: minLength(2)
|
||||
}
|
||||
}
|
||||
},
|
||||
async mounted () {
|
||||
this.$refs.name.focus = true
|
||||
if (this.modalDataID) {
|
||||
this.isEdit = true
|
||||
this.setData()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('modal', [
|
||||
'closeModal',
|
||||
'resetModalData'
|
||||
]),
|
||||
...mapActions('payment', [
|
||||
'addPaymentMode',
|
||||
'updatePaymentMode'
|
||||
]),
|
||||
resetFormData () {
|
||||
this.formData = {
|
||||
id: null,
|
||||
name: null
|
||||
}
|
||||
this.$v.formData.$reset()
|
||||
},
|
||||
async submitPaymentMode () {
|
||||
this.$v.formData.$touch()
|
||||
if (this.$v.$invalid) {
|
||||
return true
|
||||
}
|
||||
this.isLoading = true
|
||||
let response
|
||||
if (this.isEdit) {
|
||||
response = await this.updatePaymentMode(this.formData)
|
||||
if (response.data) {
|
||||
window.toastr['success'](this.$t('settings.customization.payments.payment_mode_updated'))
|
||||
this.closePaymentModeModal()
|
||||
return true
|
||||
} window.toastr['error'](response.data.error)
|
||||
} else {
|
||||
try {
|
||||
response = await this.addPaymentMode(this.formData)
|
||||
if (response.data) {
|
||||
this.isLoading = false
|
||||
window.toastr['success'](this.$t('settings.customization.payments.payment_mode_added'))
|
||||
this.closePaymentModeModal()
|
||||
return true
|
||||
} window.toastr['error'](response.data.error)
|
||||
} catch (err) {
|
||||
if (err.response.data.errors.name) {
|
||||
this.isLoading = true
|
||||
window.toastr['error'](this.$t('validation.payment_mode_already_taken'))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async setData () {
|
||||
this.formData = {
|
||||
id: this.modalData.id,
|
||||
name: this.modalData.name
|
||||
}
|
||||
},
|
||||
closePaymentModeModal () {
|
||||
this.resetModalData()
|
||||
this.resetFormData()
|
||||
this.closeModal()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -852,6 +852,8 @@
|
||||
"email_incorrect": "بريد الكتروني غير صحيح.",
|
||||
"email_already_taken": "هذا البريد الالكتروني مستخدم مسبقاً",
|
||||
"email_does_not_exist": "لا يوجد كستخدم بهذا البريد الالكتروني",
|
||||
"item_unit_already_taken": "وحدة البند قد اتخذت بالفعل",
|
||||
"payment_mode_already_taken": "لقد تم بالفعل أخذ طريقة الدفع",
|
||||
"send_reset_link": "أرسال رابط استعادة كلمة المرور",
|
||||
"not_yet": "ليس بعد؟ أعد الإرسال الآن..",
|
||||
"password_min_length": "كلمة المرور يجب أن تتكون من {count} أحرف على الأقل",
|
||||
|
||||
877
resources/assets/js/plugins/de.json
Normal file
877
resources/assets/js/plugins/de.json
Normal file
@ -0,0 +1,877 @@
|
||||
{
|
||||
"credit_notes": {
|
||||
"action": "Aktion",
|
||||
"amount": "Summe",
|
||||
"confirm_delete": "Wollen Sie diese Gutschrift löschen?",
|
||||
"contact": "Kontakt",
|
||||
"credit_notes": "Gutschriften",
|
||||
"credit_notes_list": "Gutschriften-Liste",
|
||||
"credit_number": "Kreditkarten-Nummer",
|
||||
"date": "Datum",
|
||||
"item": {
|
||||
"description": "Beschreibung",
|
||||
"discount": "Rabatt",
|
||||
"price": "Preis",
|
||||
"quantity": "Menge",
|
||||
"sub_total": "Zwischensumme",
|
||||
"tax": "Steuer",
|
||||
"title": "Titel",
|
||||
"total": "Gesamt",
|
||||
"total_discount": "Rabatt Gesamt"
|
||||
},
|
||||
"notes": "Hinweise",
|
||||
"title": "Gutschriften"
|
||||
},
|
||||
"customers": {
|
||||
"action": "Aktion",
|
||||
"add_customer": "Kunde hinzufügen",
|
||||
"add_new_customer": "Neuen Kunden hinzufügen",
|
||||
"added_on": "Hinzugefügt am",
|
||||
"address": "Adresse",
|
||||
"amount_due": "Offener Betrag",
|
||||
"basic_info": "Basisinformation",
|
||||
"billing_address": "Rechnungsadresse",
|
||||
"city": "Stadt",
|
||||
"confirm_delete": "Sie können diesen Kunden nicht wiederherstellen | Sie können diese Kunden nicht wiederherstellen",
|
||||
"contact_name": "Kontakt Name",
|
||||
"contacts_list": "Kunden-Liste",
|
||||
"copy_billing_address": "Rechnungsadresse kopieren",
|
||||
"country": "Land",
|
||||
"created_message": "Kunde erfolgreich erstellt",
|
||||
"customer": "Kunde | Kunden",
|
||||
"deleted_message": "Kunden erfolgreich gelöscht | Kunden erfolgreich gelöscht",
|
||||
"display_name": "Anzeige Name",
|
||||
"edit_customer": "Kunde bearbeiten",
|
||||
"email": "E-Mail",
|
||||
"list_of_customers": "Dieser Abschnitt enthält die Liste der Kunden.",
|
||||
"name": "Name",
|
||||
"new_customer": "Neuer Kunde",
|
||||
"no_customers": "Noch keine Kunden!",
|
||||
"no_customers_found": "Keine Kunden gefunden!",
|
||||
"password": "Passwort",
|
||||
"phone": "Telefon",
|
||||
"primary_contact_name": "Ansprechpartner",
|
||||
"primary_currency": "Primäre Währung",
|
||||
"primary_display_name": "Primärer Anzeige Name",
|
||||
"save_customer": "Kunde speichern",
|
||||
"select_a_customer": "Wählen Sie einen Kunden",
|
||||
"select_city": "Stadt wählen",
|
||||
"select_country": "Land wählen",
|
||||
"select_currency": "Währung wählen",
|
||||
"select_state": "Bundesland wählen",
|
||||
"shipping_address": "Versand-Adresse",
|
||||
"state": "Bundesland",
|
||||
"street_1": "Strasse",
|
||||
"street_2": "Adresszusatz",
|
||||
"street_number": "Hausnummer",
|
||||
"title": "Kunden",
|
||||
"type_or_click": "Eingeben oder anklicken zum auswählen",
|
||||
"update_customer": "Kunden ändern",
|
||||
"updated_message": "Kunde erfolgreich aktualisiert",
|
||||
"website": "Webseite",
|
||||
"zip_code": "PLZ"
|
||||
},
|
||||
"dashboard": {
|
||||
"cards": {
|
||||
"customers": "Kunden",
|
||||
"due_amount": "Offene Beträge",
|
||||
"estimates": "Kostenvoranschläge",
|
||||
"invoices": "Rechnungen"
|
||||
},
|
||||
"chart_info": {
|
||||
"net_income": "Einnahmen Netto",
|
||||
"total_expense": "Gesamtausgaben",
|
||||
"total_receipts": "Eingänge gesamt",
|
||||
"total_sales": "Verkäufe gesamt",
|
||||
"year": "Jahr"
|
||||
},
|
||||
"monthly_chart": {
|
||||
"title": "Umsatz & Kosten"
|
||||
},
|
||||
"recent_estimate_card": {
|
||||
"actions": "Aktionen",
|
||||
"amount_due": "Betrag",
|
||||
"customer": "Kunden",
|
||||
"date": "Datum",
|
||||
"title": "Aktuelle Kostenvoranschläge",
|
||||
"view_all": "Alle Anzeigen"
|
||||
},
|
||||
"recent_invoices_card": {
|
||||
"actions": "Aktionen",
|
||||
"amount_due": "Offener Betrag",
|
||||
"customer": "Kunden",
|
||||
"due_on": "Fällig am",
|
||||
"title": "Fällige Rechnungen",
|
||||
"view_all": "Alle Anzeigen"
|
||||
},
|
||||
"select_year": "Jahr wählen",
|
||||
"weekly_invoices": {
|
||||
"title": "Wöchentliche Rechnungen"
|
||||
}
|
||||
},
|
||||
"estimates": {
|
||||
"Estimate": "Kostenvoranschlag | Kostenvoranschläge",
|
||||
"accepted": "Angenommen",
|
||||
"action": "Aktion",
|
||||
"add_estimate": "Kostenvoranschlag hinzufügen",
|
||||
"add_item": "Fügen Sie ein Artikel hinzu",
|
||||
"add_new_estimate": "Neuen Kostenvoranschlag hinzufügen",
|
||||
"add_new_tax": "neuen Steuersatz hinzufügen",
|
||||
"add_tax": "Steuer hinzufügen",
|
||||
"all": "Alle",
|
||||
"amount": "Summe",
|
||||
"amount_due": "OFFENER BETRAG",
|
||||
"confirm_conversion": "Sie möchten, konvertieren Sie diese Schätzung in die Rechnung?",
|
||||
"confirm_delete": "Der Kostenvoranschlag kann nicht wiederhergestellt werden | Die Kostenvoranschläge können nicht wiederhergestellt werden",
|
||||
"confirm_mark_as_accepted": "Dieser Kostenvoranschlag wird als angenommen markiert",
|
||||
"confirm_mark_as_rejected": "Dieser Kostenvoranschlag wird als abgelehnt markiert",
|
||||
"confirm_mark_as_sent": "Dieser Kostenvoranschlag wird als gesendet markiert",
|
||||
"confirm_send_estimate": "Der Kostenvoranschlag wird per E-Mail an den Kunden gesendet",
|
||||
"contact": "Kontakt",
|
||||
"conversion_message": "Rechnung erfolgreich erstellt",
|
||||
"convert_to_invoice": "Konvertieren in Rechnung",
|
||||
"created_message": "Kostenvoranschlag erfolgreich erstellt",
|
||||
"customer": "KUNDEN",
|
||||
"date": "Datum",
|
||||
"days": "{days} Tage",
|
||||
"declined": "Abgelehnt",
|
||||
"deleted_message": "Kostenvoranschlag erfolgreich gelöscht | Kostenvoranschläge erfolgreich gelöscht",
|
||||
"discount": "Rabatt",
|
||||
"draft": "Entwurf",
|
||||
"due_date": "Fälligkeit",
|
||||
"edit_estimate": "Kostenvoranschlag ändern",
|
||||
"errors": {
|
||||
"required": "Feld ist erforderlich"
|
||||
},
|
||||
"estimate": "Kostenvoranschlag | Kostenvoranschläge",
|
||||
"estimate_number": "Kostenvoran. Nummer",
|
||||
"estimate_template": "Vorlage",
|
||||
"estimates_list": "Liste Kostenvoranschläge",
|
||||
"expiry_date": "Zahlungsziel",
|
||||
"item": {
|
||||
"amount": "Summe",
|
||||
"description": "Beschreibung",
|
||||
"discount": "Rabatt",
|
||||
"price": "Preis",
|
||||
"quantity": "Menge",
|
||||
"select_an_item": "Wählen Sie einen Artikel",
|
||||
"sub_total": "Zwischensumme",
|
||||
"tax": "Steuer",
|
||||
"title": "Titel",
|
||||
"total": "Gesamt",
|
||||
"total_discount": "Rabatt Gesamt",
|
||||
"type_item_description": "Artikel Beschreibung (optional)"
|
||||
},
|
||||
"items": "Artikel",
|
||||
"list_of_estimates": "Dieser Abschnitt enthält die Liste der Kostenvoranschläge.",
|
||||
"mark_as_accepted": "Markiert als angenommen",
|
||||
"mark_as_rejected": "Markiert als abgelehnt",
|
||||
"mark_as_sent": "Als gesendet markieren",
|
||||
"mark_as_sent_successfully": "Kostenvoranschlag als gesendet markiert.",
|
||||
"marked_as_accepted_message": "Kostenvoranschlag als angenommen markiert",
|
||||
"marked_as_rejected_message": "Kostenvoranschlag als abgelehnt markiert",
|
||||
"months": "{months} Monat",
|
||||
"new_estimate": "Neuer Kostenvoranschlag",
|
||||
"no_estimates": "Keine Kostenvoranschläge vorhanden!",
|
||||
"no_matching_estimates": "Es gibt keine übereinstimmenden Kostenvoranschläge!",
|
||||
"notes": "Hinweise",
|
||||
"number": "ANZAHL",
|
||||
"paid": "Bezahlt",
|
||||
"partially_paid": "Teilweise bezahlt",
|
||||
"record_payment": "Zahlung erfassen",
|
||||
"ref_no": "REF. - NR.",
|
||||
"ref_number": "Ref-Nummer",
|
||||
"save_estimate": "Kostenvoranschlag speichern",
|
||||
"send_estimate": "Kostenvoranschlag senden",
|
||||
"send_estimate_successfully": "Kostenvoranschlag erfolgreich gesendet",
|
||||
"sent": "Gesendet",
|
||||
"something_went_wrong": "Da ging etwas schief",
|
||||
"status": "Status",
|
||||
"sub_total": "Zwischensumme",
|
||||
"tax": "Steuer",
|
||||
"title": "Kostenvoranschläge",
|
||||
"total": "Gesamt",
|
||||
"unpaid": "Unbezahlte",
|
||||
"update_Estimate": "Kostenvoranschlag aktualisieren",
|
||||
"updated_message": "Kostenvoranschlag erfolgreich aktualisiert",
|
||||
"user_email_does_not_exist": "Benutzer-E-Mail nicht vorhanden",
|
||||
"years": "{years} Jahre"
|
||||
},
|
||||
"expenses": {
|
||||
"action": "Aktion",
|
||||
"add_expense": "Aufwendung hinzufügen",
|
||||
"add_new_expense": "Neue Aufwendung hinzufügen",
|
||||
"amount": "Summe",
|
||||
"categories": {
|
||||
"actions": "Aktionen",
|
||||
"add_category": "Kategorie hinzufügen",
|
||||
"amount": "Summe",
|
||||
"categories_list": "Liste der Kategorien",
|
||||
"category": "Kategorie | Kategorien",
|
||||
"description": "Beschreibung",
|
||||
"name": "Name",
|
||||
"new_category": "Neue Kategorie",
|
||||
"select_a_category": "Wählen Sie eine Kategorie",
|
||||
"title": "Titel"
|
||||
},
|
||||
"category": "Kategorie",
|
||||
"category_id": "Kategorie-Id",
|
||||
"confirm_delete": "Sie können diese Ausgabe nicht wiederherstellen. | Sie können diese Ausgaben nicht wiederherstellen.",
|
||||
"contact": "Kontakt",
|
||||
"created_message": "Aufwand erfolgreich erstellt",
|
||||
"date": "Aufwandsdatum",
|
||||
"deleted_message": "Aufwand erfolgreich gelöscht | Aufwand erfolgreich gelöscht",
|
||||
"description": "Beschreibung",
|
||||
"download_receipt": "Quittung herunterladen",
|
||||
"edit_expense": "Aufwendung ändern",
|
||||
"expense": "Aufwendung | Aufwendungen",
|
||||
"expense_date": "Datum",
|
||||
"expense_title": "Titel",
|
||||
"expenses_list": "Liste der Ausgaben",
|
||||
"from_date": "Von Datum",
|
||||
"list_of_expenses": "Dieser Abschnitt enthält die Liste der Ausgaben.",
|
||||
"new_expense": "Neue Aufwendung",
|
||||
"no_expenses": "Noch keine Ausgaben!",
|
||||
"note": "Hinweis",
|
||||
"receipt": "Eingang",
|
||||
"save_expense": "Aufwendung speichern",
|
||||
"title": "Aufwendungen/Ausgaben",
|
||||
"to_date": "bis Datum",
|
||||
"update_expense": "Aufwendung aktualisieren",
|
||||
"updated_message": "Aufwand erfolgreich aktualisiert"
|
||||
},
|
||||
"general": {
|
||||
"action_failed": "Aktion fehlgeschlagen",
|
||||
"actions": "Aktionen",
|
||||
"add_new_item": "Artikel hinzufügen",
|
||||
"all": "Alle",
|
||||
"are_you_sure": "Sind Sie sicher?",
|
||||
"back_to_login": "Zurück zum Login?",
|
||||
"bill_to": "Rechnungsempfänger",
|
||||
"bytefury": "Bytefury",
|
||||
"cancel": "Abrechen",
|
||||
"choose": "Wählen",
|
||||
"choose_file": "Klicken Sie hier, um eine Datei auszuwählen",
|
||||
"choose_template": "Wählen Sie eine Vorlage",
|
||||
"clear_all": "Alle entfernen",
|
||||
"delete": "Löschen",
|
||||
"discount": "RABATT",
|
||||
"download": "Download",
|
||||
"download_pdf": "Download PDF",
|
||||
"draft": "Entwurf",
|
||||
"due": "Fällig",
|
||||
"edit": "Ändern",
|
||||
"filter": "Filter",
|
||||
"fixed": "Behoben",
|
||||
"four_zero_four": "Vier hundert vier",
|
||||
"from": "Von",
|
||||
"from_date": "Von Datum",
|
||||
"go_back": "zurück",
|
||||
"go_home": "Geh zurück",
|
||||
"home": "Startseite",
|
||||
"list_is_empty": "Liste ist leer.",
|
||||
"no_tax_found": "Kein Steuersatz gefunden!",
|
||||
"of": "von",
|
||||
"percentage": "Prozentsatz",
|
||||
"powered_by": "Powered by",
|
||||
"remove": "Entfernen",
|
||||
"save": "Speichern",
|
||||
"search": "Suchen",
|
||||
"select_a_status": "Status wählen",
|
||||
"select_a_tax": "Steuersatz wählen",
|
||||
"select_all": "Alle auswählen",
|
||||
"select_city": "Stadt wählen",
|
||||
"select_country": "Land wählen",
|
||||
"select_state": "Bundesland wählen",
|
||||
"sent": "Gesendet",
|
||||
"setting_updated": "Einstellungen erfolgreich aktualisiert",
|
||||
"ship_to": "Versand ein",
|
||||
"showing": "Anzeigen",
|
||||
"street_1": "Straße",
|
||||
"street_2": "Zusatz Strasse",
|
||||
"subtotal": "ZWISCHENSUMME",
|
||||
"tax": "Steuer",
|
||||
"to": "bis",
|
||||
"to_date": "bis Datum",
|
||||
"total_amount": "GESAMTSUMME",
|
||||
"update": "Update",
|
||||
"view": "Anzeigen",
|
||||
"view_pdf": "PDF anzeigen",
|
||||
"you_got_lost": "Hoppla! Du hast dich verirrt!"
|
||||
},
|
||||
"invoices": {
|
||||
"action": "Aktion",
|
||||
"add_item": "Fügen Sie ein Artikel hinzu",
|
||||
"add_new_invoice": "Neue Rechnung hinzufügen",
|
||||
"add_new_tax": "Neuen Steuersatz hinzufügen",
|
||||
"add_tax": "Steuersatz hinzufügen",
|
||||
"all": "Alle",
|
||||
"amount": "Summe",
|
||||
"amount_due": "OFFENER BETRAG",
|
||||
"confirm_delete": "Sie können diese Rechnung nicht wiederherstellen. | Sie können diese Rechnungen nicht wiederherstellen.",
|
||||
"confirm_send": "Diese Rechnung wird per E-Mail an den Kunden gesendet",
|
||||
"confirm_send_invoice": "Diese Rechnung wird per E-Mail an den Kunden gesendet",
|
||||
"contact": "Kontakt",
|
||||
"created_message": "Rechnung erfolgreich erstellt",
|
||||
"customer": "KUNDEN",
|
||||
"date": "Datum",
|
||||
"days": "{days} Tage",
|
||||
"deleted_message": "Rechnung erfolgreich gelöscht | Rechnungen erfolgreich gelöscht",
|
||||
"discount": "Rabatt",
|
||||
"due_date": "Fälligkeit",
|
||||
"edit_invoice": "Rechnung bearbeiten",
|
||||
"invalid_due_amount_message": "Der Gesamtrechnungsbetrag darf nicht kleiner sein als der für diese Rechnung bezahlte Gesamtbetrag. Bitte aktualisieren Sie die Rechnung oder löschen Sie die zugehörigen Zahlungen um fortzufahren.",
|
||||
"invoice": "Rechnung | Rechnungen",
|
||||
"invoice_date": "Rechnungsdatum",
|
||||
"invoice_mark_as_sent": "Diese Rechnung wird als gesendet markiert",
|
||||
"invoice_number": "Rechnungsnummer",
|
||||
"invoice_template": "Rechnungs-Vorlage",
|
||||
"invoices_list": "Liste der Rechnungen",
|
||||
"item": {
|
||||
"amount": "Summe",
|
||||
"description": "Beschreibung",
|
||||
"discount": "Rabatt",
|
||||
"price": "Preis",
|
||||
"quantity": "Menge",
|
||||
"select_an_item": "Geben Sie oder wählen Sie ein Artikel",
|
||||
"sub_total": "Zwischensumme",
|
||||
"tax": "Steuer",
|
||||
"title": "Titel",
|
||||
"total": "Gesamt",
|
||||
"total_discount": "Rabatt Gesamt",
|
||||
"type_item_description": "Artikel Beschreibung (optional)"
|
||||
},
|
||||
"list_of_invoices": "Dieser Abschnitt enthält die Liste der Rechnungen.",
|
||||
"mark_as_sent": "Als gesendet markieren",
|
||||
"mark_as_sent_successfully": "Rechnung gekennzeichnet als erfolgreich gesendet",
|
||||
"marked_as_sent_message": "Rechnung als erfolgreich gesendet markiert",
|
||||
"months": "{months} Monat",
|
||||
"new_invoice": "Neue Rechnung",
|
||||
"no_invoices": "Keine Rechnungen vorhanden!",
|
||||
"no_matching_invoices": "Es gibt keine entsprechenden Rechnungen!",
|
||||
"notes": "Hinweise",
|
||||
"number": "ANZAHL",
|
||||
"paid": "Bezahlt",
|
||||
"paid_status": "BEZAHLT-STATUS",
|
||||
"partially_paid": "Teilzahlung",
|
||||
"payment_attached_message": "Einer der ausgewählten Rechnungen ist bereits eine Zahlung zugeordnet. Stellen Sie sicher, dass Sie zuerst die angehängten Zahlungen löschen, um mit dem Entfernen fortzufahren",
|
||||
"record_payment": "Zahlung erfassen",
|
||||
"ref_no": "REF. - NR.",
|
||||
"ref_number": "Ref-Nummer",
|
||||
"save_invoice": "Rechnung speichern",
|
||||
"select_invoice": "Wählen Sie eine Rechnung",
|
||||
"send_invoice": "Rechnung senden",
|
||||
"send_invoice_successfully": "Rechnung erfolgreich versendet",
|
||||
"something_went_wrong": "Da ist etwas schief gelaufen",
|
||||
"status": "Status",
|
||||
"sub_total": "Zwischensumme",
|
||||
"template": "Vorlage",
|
||||
"title": "Rechnungen",
|
||||
"total": "Gesamt",
|
||||
"unpaid": "Unbezahlte",
|
||||
"update_expense": "Kosten aktualisieren",
|
||||
"update_invoice": "Rechnung ändern",
|
||||
"updated_message": "Rechnung erfolgreich aktualisiert",
|
||||
"user_email_does_not_exist": "Benutzer-E-Mail existiert nicht",
|
||||
"view": "Anzeigen",
|
||||
"years": "{years} Jahre"
|
||||
},
|
||||
"items": {
|
||||
"action": "Aktion",
|
||||
"add_item": "Artikel hinzufügen",
|
||||
"add_new_item": "Neuen Artikel hinzufügen",
|
||||
"added_on": "Hinzugefügt am",
|
||||
"confirm_delete": "Sie können diesen Artikel nicht wiederherstellen | Sie können diese Artikel nicht wiederherstellen",
|
||||
"created_message": "Artikel erfolgreich erstellt",
|
||||
"date_of_creation": "Erstellt am",
|
||||
"deleted_message": "Artikel erfolgreich gelöscht | Artikel erfolgreich gelöscht",
|
||||
"description": "Beschreibung",
|
||||
"edit_item": "Artikel bearbeiten",
|
||||
"item": "Artikel | Artikel",
|
||||
"item_attached_message": "Ein Artikel der bereits verwendet wird kann nicht gelöscht werden",
|
||||
"items_list": "Artikel-Liste",
|
||||
"list_of_items": "Dieser Abschnitt enthält die Liste der Artikel.",
|
||||
"name": "Name",
|
||||
"new_item": "Neuer Artikel",
|
||||
"no_items": "Keine Artikel vorhanden!",
|
||||
"price": "Preis",
|
||||
"save_item": "Artikel speichern",
|
||||
"select_a_unit": "wählen Sie die Einheit",
|
||||
"title": "Artikel",
|
||||
"unit": "Einheit",
|
||||
"update_item": "Artikel ändern",
|
||||
"updated_message": "Artikel erfolgreich aktualisiert"
|
||||
},
|
||||
"layout_login": {
|
||||
"copyright_crater": "Copyright @ Crater - 2019",
|
||||
"crater_help": "Crater helps you track expenses, record payments & generate beautiful",
|
||||
"for_freelancer": "for Freelancers &",
|
||||
"invoices_and_estimates": "invoices & estimates with ability to choose multiple templates.",
|
||||
"small_businesses": "Small Businesses ",
|
||||
"super_simple_invoicing": "Super Simple Invoicing"
|
||||
},
|
||||
"login": {
|
||||
"email": "E-Mail",
|
||||
"enter_email": "Geben Sie Ihre E-Mail ein",
|
||||
"enter_password": "Geben Sie das Passwort ein",
|
||||
"forgot_password": "Passwort vergessen?",
|
||||
"login": "Anmelden",
|
||||
"login_placeholder": "mail@example.com",
|
||||
"or_signIn_with": "oder Anmelden mit",
|
||||
"password": "Passwort",
|
||||
"password_reset_successfully": "Passwort erfolgreich zurückgesetzt",
|
||||
"register": "Registrieren",
|
||||
"reset_password": "Passwort zurücksetzen",
|
||||
"retype_password": "Passwort bestätigen"
|
||||
},
|
||||
"navigation": {
|
||||
"customers": "Kunden",
|
||||
"dashboard": "Übersicht",
|
||||
"estimates": "Kostenvoranschläge",
|
||||
"expenses": "Kosten",
|
||||
"invoices": "Rechnungen",
|
||||
"items": "Artikel",
|
||||
"logout": "Abmelden",
|
||||
"payments": "Zahlungen",
|
||||
"reports": "Berichte",
|
||||
"settings": "Einstellungen"
|
||||
},
|
||||
"payments": {
|
||||
"action": "Aktion",
|
||||
"add_new_payment": "Neue Zahlung hinzufügen",
|
||||
"add_payment": "Zahlung hinzufügen",
|
||||
"amount": "Summe",
|
||||
"confirm_delete": "Sie können diese Zahlung nicht wiederherstellen. | Sie können diese Zahlungen nicht wiederherstellen.",
|
||||
"created_message": "Zahlung erfolgreich erstellt",
|
||||
"customer": "Kunden",
|
||||
"date": "Datum",
|
||||
"deleted_message": "Zahlung erfolgreich gelöscht | Zahlungen erfolgreich gelöscht",
|
||||
"edit_payment": "Zahlung bearbeiten",
|
||||
"invalid_amount_message": "Zahlungsbetrag ist ungültig",
|
||||
"invoice": "Rechnung",
|
||||
"list_of_payments": "Dieser Abschnitt enthält die Liste der Zahlungen.",
|
||||
"new_payment": "Neue Zahlung",
|
||||
"no_payments": "Keine Zahlungen vorhanden!",
|
||||
"note": "Hinweis",
|
||||
"payment": "Zahlung | Zahlungen",
|
||||
"payment_mode": "Zahlungsart",
|
||||
"payment_number": "Zahlungsnummer",
|
||||
"payments_list": "Liste der Zahlungen",
|
||||
"record_payment": "Zahlung eintragen",
|
||||
"save_payment": "Zahlung speichern",
|
||||
"select_payment_mode": "Wählen Sie den Zahlungsmodus",
|
||||
"title": "Zahlungen",
|
||||
"update_payment": "Zahlung ändern",
|
||||
"updated_message": "Zahlung erfolgreich aktualisiert",
|
||||
"view_payment": "Zahlung anzeigen"
|
||||
},
|
||||
"reports": {
|
||||
"download_pdf": "Download PDF",
|
||||
"errors": {
|
||||
"required": "Feld ist erforderlich"
|
||||
},
|
||||
"estimates": {
|
||||
"amount": "Summe",
|
||||
"contact_name": "Ansprechpartner",
|
||||
"due_date": "Fälligkeit",
|
||||
"estimate": "Kostenvoranschlag",
|
||||
"estimate_date": "Datum Kostenvoranschlag",
|
||||
"estimate_number": "Kostenvoranschlag-Nr.",
|
||||
"ref_number": "Ref-Nummer",
|
||||
"status": "Status"
|
||||
},
|
||||
"expenses": {
|
||||
"amount": "Summe",
|
||||
"category": "Kategorie",
|
||||
"date": "Datum",
|
||||
"date_range": "Datumsbereich auswählen",
|
||||
"expenses": "Aufwendungen",
|
||||
"from_date": "Ab Datum",
|
||||
"to_date": "bis Datum"
|
||||
},
|
||||
"from_date": "Ab Datum",
|
||||
"invoices": {
|
||||
"amount": "Summe",
|
||||
"contact_name": "Ansprechpartner",
|
||||
"due_date": "Fälligkeit",
|
||||
"invoice": "Rechnung",
|
||||
"invoice_date": "Rechnungsdatum",
|
||||
"status": "Status"
|
||||
},
|
||||
"paid": "Bezahlt",
|
||||
"profit_loss": {
|
||||
"date_range": "Datumsbereich auswählen",
|
||||
"from_date": "Ab Datum",
|
||||
"profit_loss": "Gewinn & Verlust",
|
||||
"to_date": "bis Datum"
|
||||
},
|
||||
"report": "Bericht | Berichte",
|
||||
"sales": {
|
||||
"date_range": "Datumsbereich auswählen",
|
||||
"from_date": "Ab Datum",
|
||||
"report_type": "Berichtstyp",
|
||||
"sales": "Vertrieb",
|
||||
"to_date": "bis Datum"
|
||||
},
|
||||
"status": "Status",
|
||||
"taxes": {
|
||||
"date_range": "Datumsbereich auswählen",
|
||||
"from_date": "Ab Datum",
|
||||
"taxes": "Steuern",
|
||||
"to_date": "bis Datum"
|
||||
},
|
||||
"title": "Bericht",
|
||||
"to_date": "bis Datum",
|
||||
"unpaid": "Unbezahlt",
|
||||
"update_report": "Bericht aktualisieren",
|
||||
"view_pdf": "PDF anzeigen"
|
||||
},
|
||||
"settings": {
|
||||
"account_settings": {
|
||||
"account_settings": "Konto-Einstellungen",
|
||||
"confirm_password": "Kennwort Bestätigen",
|
||||
"email": "E-Mail",
|
||||
"name": "Name",
|
||||
"password": "Passwort",
|
||||
"profile_picture": "Profil Bild",
|
||||
"save": "Speichern",
|
||||
"section_description": "Sie können Ihren Namen, Ihre E-Mail-Adresse und Ihr Passwort mit dem folgenden Formular aktualisieren.",
|
||||
"updated_message": "Kontoeinstellungen erfolgreich aktualisiert"
|
||||
},
|
||||
"company_info": {
|
||||
"address": "Adresse",
|
||||
"city": "Stadt",
|
||||
"company_info": "Firmeninfo",
|
||||
"company_logo": "Firmenlogo",
|
||||
"company_name": "Name des Unternehmens",
|
||||
"country": "Land",
|
||||
"phone": "Telefon",
|
||||
"save": "Speichern",
|
||||
"section_description": "Informationen zu Ihrem Unternehmen, die auf Rechnungen, Kostenvoranschlägen und anderen von Crater erstellten Dokumenten angezeigt werden.",
|
||||
"state": "Bundesland",
|
||||
"updated_message": "Unternehmensinformationen wurden erfolgreich aktualisiert",
|
||||
"zip": "PLZ"
|
||||
},
|
||||
"currencies": {
|
||||
"action": "Aktion",
|
||||
"add_currency": "Währung einfügen",
|
||||
"code": "Code",
|
||||
"currencies_list": "Währungen Liste",
|
||||
"currency": "Währung | Währungen",
|
||||
"decimal_separator": "Decimal-Separator",
|
||||
"left": "Links",
|
||||
"name": "Name",
|
||||
"position": "Position",
|
||||
"position_of_symbol": "Position des Währungssymbol",
|
||||
"precision": "Präzision",
|
||||
"right": "Rechts",
|
||||
"select_currency": "Währung wählen",
|
||||
"symbol": "Symbol",
|
||||
"thousand_separator": "Tausendertrennzeichen",
|
||||
"title": "Währungen"
|
||||
},
|
||||
"customization": {
|
||||
"addresses": {
|
||||
"address": "Adresse",
|
||||
"address_setting_updated": "Adresse-Einstellung erfolgreich aktualisiert",
|
||||
"address_street_1": "Strasse",
|
||||
"address_street_2": "Zusatz Strasse",
|
||||
"city": "Stadt",
|
||||
"company_address": "Firma Adresse",
|
||||
"company_name": "Name des Unternehmens",
|
||||
"contact": "Kontakt",
|
||||
"country": "Land",
|
||||
"customer_billing_address": "Rechnungsadresse des Kunden",
|
||||
"customer_shipping_address": "Versand-Adresse des Kunden",
|
||||
"display_name": "Anzeigename",
|
||||
"email": "E-Mail",
|
||||
"insert_fields": "Felder einfügen",
|
||||
"name": "Name",
|
||||
"phone": "Telefon",
|
||||
"primary_contact_name": "Ansprechpartner",
|
||||
"section_description": "Sie können die Rechnungsadresse und das Versandadressenformat des Kunden festlegen (nur in PDF angezeigt). ",
|
||||
"state": "Bundesland",
|
||||
"title": "Adressen",
|
||||
"website": "Website",
|
||||
"zip_code": "PLZ"
|
||||
},
|
||||
"customization": "Anpassung",
|
||||
"estimates": {
|
||||
"autogenerate_estimate_number": "Kostenvoranschlagsnummer automatisch generieren",
|
||||
"enter_estimate_prefix": "Geben Sie das Kostenvoranschlag Präfix ein",
|
||||
"estimate_prefix": "Kostenvoranschlag Präfix",
|
||||
"estimate_setting_description": "Deaktivieren Sie diese Option, wenn Sie nicht jedes Mal, wenn Sie einen neue Kostenvoranschlag erstellen, automatisch eine Schätzung generieren möchten.",
|
||||
"estimate_setting_updated": "Einstellungen Kostenvoranschläge erfolgreich aktualisiert",
|
||||
"estimate_settings": "Einstellungen Kostenvoranschlag",
|
||||
"title": "Kostenvoranschläge"
|
||||
},
|
||||
"invoices": {
|
||||
"autogenerate_invoice_number": "Rechnungsnummer automatisch generieren",
|
||||
"enter_invoice_prefix": "Rechnungspräfix eingeben",
|
||||
"invoice_prefix": "Rechnung Präfix",
|
||||
"invoice_setting_description": "Deaktivieren Sie diese Option, wenn Sie Rechnungsnummern nicht jedes Mal automatisch generieren möchten, wenn Sie eine neue Rechnung erstellen.",
|
||||
"invoice_setting_updated": "Rechnungseinstellung erfolgreich aktualisiert",
|
||||
"invoice_settings": "Rechnungseinstellungen",
|
||||
"notes": "Hinweise",
|
||||
"terms_and_conditions": "Allgemeine Geschäftsbedingungen",
|
||||
"title": "Rechnungen"
|
||||
},
|
||||
"payments": {
|
||||
"autogenerate_payment_number": "Zahlungsnummer automatisch generieren",
|
||||
"enter_payment_prefix": "Zahlungspräfix eingeben",
|
||||
"payment_prefix": "Zahlung Präfix",
|
||||
"payment_setting_description": "Deaktivieren Sie diese Option, wenn Sie nicht jedes Mal, wenn Sie eine neue Zahlung erstellen, automatisch Zahlungsnummern generieren möchten.",
|
||||
"payment_setting_updated": "Zahlungseinstellung erfolgreich aktualisiert",
|
||||
"payment_settings": "Zahlung Einstellungen",
|
||||
"title": "Zahlungen"
|
||||
},
|
||||
"save": "Speichern",
|
||||
"updated_message": "Unternehmensinformationen wurden erfolgreich aktualisiert"
|
||||
},
|
||||
"date_format": "Datum-Format",
|
||||
"expense_category": {
|
||||
"action": "Aktion",
|
||||
"add_new_category": "Neue Kategorie hinzufügen",
|
||||
"already_in_use": "Kategorie wird bereits verwendet",
|
||||
"category_description": "Beschreibung",
|
||||
"category_name": "Kategorie Name",
|
||||
"confirm_delete": "Sie können diese Ausgabenkategorie nicht wiederherstellen",
|
||||
"created_message": "Ausgabenkategorie erfolgreich erstellt",
|
||||
"deleted_message": "Ausgabenkategorie erfolgreich gelöscht",
|
||||
"description": "Für das Hinzufügen von Ausgabeneinträgen sind Kategorien erforderlich. Sie können diese Kategorien nach Ihren Wünschen hinzufügen oder entfernen.",
|
||||
"title": "Kategorien Kosten",
|
||||
"updated_message": "Ausgabenkategorie erfolgreich aktualisiert"
|
||||
},
|
||||
"general": "Allgemeine",
|
||||
"language": "Sprache",
|
||||
"mail": {
|
||||
"driver": "E-Mail Treiber",
|
||||
"encryption": "E-Mail-Verschlüsselung",
|
||||
"from_mail": "Von E-Mail-Adresse",
|
||||
"from_name": "Von E-Mail-Namen",
|
||||
"host": "E-Mail Mailserver",
|
||||
"mail_config": "E-Mail-Konfiguration",
|
||||
"mail_config_desc": "Unten finden Sie das Formular zum Konfigurieren des E-Mail-Treibers zum Senden von E-Mails über die App. Sie können auch Drittanbieter wie Sendgrid, SES usw. konfigurieren.",
|
||||
"mailgun_domain": "Domain",
|
||||
"mailgun_endpoint": "Mailgun-Endpunkt",
|
||||
"mailgun_secret": "Mailgun Verschlüsselung",
|
||||
"password": "E-Mail-Kennwort",
|
||||
"port": "E-Mail Port",
|
||||
"secret": "Verschlüsselung",
|
||||
"ses_key": "SES-Taste",
|
||||
"ses_secret": "SES Verschlüsselung",
|
||||
"username": "E-Mail-Benutzername"
|
||||
},
|
||||
"menu_title": {
|
||||
"account_settings": "Konto-Einstellungen",
|
||||
"company_information": "Informationen zum Unternehmen",
|
||||
"customization": "Anpassung",
|
||||
"expense_category": "Ausgabenkategorien",
|
||||
"notifications": "Benachrichtigungen",
|
||||
"preferences": "Einstellungen",
|
||||
"tax_types": "Steuersätze",
|
||||
"update_app": "Update App"
|
||||
},
|
||||
"notification": {
|
||||
"description": "Welche E-Mail-Benachrichtigungen möchten Sie erhalten wenn sich etwas ändert?",
|
||||
"email": "Benachrichtigungen senden an",
|
||||
"email_save_message": "Email erfolgreich gespeichert",
|
||||
"estimate_viewed": "Kostenvoranschlag angesehen",
|
||||
"estimate_viewed_desc": "Wenn Ihr Kunde den gesendeten Kostenvoranschlag anzeigt bekommt.",
|
||||
"invoice_viewed": "Rechnung angezeigt",
|
||||
"invoice_viewed_desc": "Wenn Ihr Kunde die gesendete Rechnung anzeigt bekommt.",
|
||||
"please_enter_email": "Bitte E-Mail eingeben",
|
||||
"save": "Speichern",
|
||||
"title": "Benachrichtigung"
|
||||
},
|
||||
"pdf": {
|
||||
"footer_text": "Fußzeile Text",
|
||||
"pdf_layout": "PDF-Layout",
|
||||
"title": "PDF-Einstellung"
|
||||
},
|
||||
"preferences": {
|
||||
"currency": "Währung",
|
||||
"date_format": "Datum-Format",
|
||||
"discount_per_item": "Rabatt pro Artikel ",
|
||||
"discount_setting": "Einstellung Rabatt",
|
||||
"discount_setting_description": "Aktivieren Sie diese Option, wenn Sie einzelnen Rechnungspositionen einen Rabatt hinzufügen möchten. Standardmäßig wird der Rabatt direkt zur Rechnung hinzugefügt.",
|
||||
"fiscal_year": "Geschäftsjahr",
|
||||
"general_settings": "Standardeinstellungen für das System.",
|
||||
"language": "Sprache",
|
||||
"preference": "Präferenz | Präferenzen",
|
||||
"save": "Speichern",
|
||||
"select_date_formate": "select Date Formate",
|
||||
"select_financial_year": "Geschäftsjahr auswählen",
|
||||
"select_language": "Sprache auswählen",
|
||||
"select_time_zone": "Zeitzone auswählen",
|
||||
"time_zone": "Zeitzone",
|
||||
"updated_message": "Einstellungen erfolgreich aktualisiert"
|
||||
},
|
||||
"primary_currency": "Primäre Währung",
|
||||
"setting": "Einstellung | Einstellungen",
|
||||
"tax_types": {
|
||||
"action": "Aktion",
|
||||
"add_new_tax": "Neuen Steuersatz hinzufügen",
|
||||
"add_tax": "Steuersätze hinzufügen",
|
||||
"already_in_use": "Steuersatz wird bereits verwendet",
|
||||
"compound_tax": "Compound Tax",
|
||||
"confirm_delete": "Sie können diesen Steuersatz nicht wiederherstellen",
|
||||
"created_message": "Steuersatz erfolgreich erstellt",
|
||||
"deleted_message": "Steuersatz erfolgreich gelöscht",
|
||||
"description": "Sie können Steuern nach Belieben hinzufügen oder entfernen. Crater unterstützt Steuern auf einzelne Artikel sowie auf die Rechnung.",
|
||||
"percent": "Prozent",
|
||||
"tax_name": "Name des Steuersatzes",
|
||||
"tax_per_item": "Steuersatz pro Artikel",
|
||||
"tax_setting_description": "Aktivieren Sie diese Option, wenn Sie den Steuersatz zu einzelnen Rechnungspositionen hinzufügen möchten. Standardmäßig wird der Steuersatz direkt zur Rechnung hinzugefügt.",
|
||||
"tax_settings": "Einstellungen Steuersatz",
|
||||
"title": "Steuersätze",
|
||||
"updated_message": "Steuersatz erfolgreich aktualisiert"
|
||||
},
|
||||
"timezone": "Zeitzone",
|
||||
"title": "Einstellungen",
|
||||
"update_app": {
|
||||
"avail_update": "Neues Update verfügbar",
|
||||
"check_update": "Nach Updates suchen",
|
||||
"current_version": "Aktuelle Version",
|
||||
"description": "Sie können Crater ganz einfach aktualisieren, indem Sie auf die Schaltfläche unten klicken, um nach einem neuen Update zu suchen.",
|
||||
"latest_message": "Kein Update verfügbar! Du bist auf der neuesten Version.",
|
||||
"next_version": "Nächste Version",
|
||||
"progress_text": "Es dauert nur ein paar Minuten. Bitte aktualisieren Sie den Bildschirm nicht und schließen Sie das Fenster nicht, bevor das Update abgeschlossen ist.",
|
||||
"title": "Update App",
|
||||
"update": "Jetzt aktualisieren",
|
||||
"update_progress": "Update läuft ...",
|
||||
"update_success": "App wurde aktualisiert! Bitte warten Sie, während Ihr Browserfenster automatisch neu geladen wird."
|
||||
},
|
||||
"user_profile": {
|
||||
"confirm_password": "Kennwort bestätigen",
|
||||
"email": "E-Mail",
|
||||
"name": "Name",
|
||||
"password": "Passwort"
|
||||
}
|
||||
},
|
||||
"tax_types": {
|
||||
"compound_tax": "zusammengesetzte Steuer",
|
||||
"description": "Beschreibung",
|
||||
"name": "Name",
|
||||
"percent": "Prozent"
|
||||
},
|
||||
"validation": {
|
||||
"address_maxlength": "Die Adresse sollte nicht länger als 255 Zeichen sein.",
|
||||
"amount_maxlength": "Der Betrag sollte nicht größer als 20 Ziffern sein.",
|
||||
"amount_minvalue": "Betrag sollte größer als 0 sein.",
|
||||
"characters_only": "Nur Zeichen.",
|
||||
"description_maxlength": "Die Beschreibung sollte nicht länger als 255 Zeichen sein.",
|
||||
"email_already_taken": "Die E-Mail ist bereits vergeben.",
|
||||
"email_does_not_exist": "Benutzer mit der angegebenen E-Mail existiert nicht",
|
||||
"email_incorrect": "Falsche E-Mail.",
|
||||
"item_unit_already_taken": "Die Artikeleinheit wurde bereits vergeben",
|
||||
"payment_mode_already_taken": "Der Zahlungsmodus wurde bereits verwendet",
|
||||
"enter_valid_tax_rate": "Geben Sie einen gültige Steuersatz ein",
|
||||
"invalid_url": "Ungültige URL (Bsp.: http://www.crater.com)",
|
||||
"maximum_options_error": "Maximal {max} Optionen ausgewählt. Entfernen Sie zuerst eine ausgewählte Option, um eine andere auszuwählen.",
|
||||
"name_min_length": "Name muss mindestens {count} Zeichen enthalten.",
|
||||
"not_yet": "Noch erhalten? Erneut senden",
|
||||
"notes_maxlength": "Notizen sollten nicht länger als 255 Zeichen sein.",
|
||||
"numbers_only": "Nur Zahlen.",
|
||||
"password_incorrect": "Passwörter müssen identisch sein",
|
||||
"password_length": "Passwort muss {count} Zeichen lang sein.",
|
||||
"password_min_length": "Password muß {count} Zeichen enthalten",
|
||||
"payment_greater_than_due_amount": "Die eingegebene Zahlung ist mehr als der fällige Betrag dieser Rechnung.",
|
||||
"payment_greater_than_zero": "Die Zahlung muss größer als 0 sein.",
|
||||
"prefix_maxlength": "Das Präfix sollte nicht länger als 5 Zeichen sein.",
|
||||
"price_greater_than_zero": "Preis muss größer als 0 sein.",
|
||||
"price_maxlength": "Der Preis sollte nicht größer als 20 Ziffern sein.",
|
||||
"price_minvalue": "Der Preis sollte größer als 0 sein.",
|
||||
"qty_must_greater_than_zero": "Die Menge muss größer als 0 sein.",
|
||||
"quantity_maxlength": "Die Menge sollte nicht größer als 20 Ziffern sein.",
|
||||
"ref_number_maxlength": "Ref Number sollte nicht länger als 255 Zeichen sein.",
|
||||
"required": "Feld ist erforderlich",
|
||||
"send_reset_link": "Link zum Zurücksetzen senden"
|
||||
},
|
||||
"wizard": {
|
||||
"account_info": "Account-Informationen",
|
||||
"account_info_desc": "Die folgenden Details werden zum Erstellen des Hauptadministratorkontos verwendet. Sie können die Details auch jederzeit nach dem Anmelden ändern.",
|
||||
"address": "Adresse",
|
||||
"city": "Stadt",
|
||||
"company_info": "Unternehmensinformationen",
|
||||
"company_info_desc": "Diese Informationen werden auf Rechnungen angezeigt. Beachten Sie, dass Sie diese später auf der Einstellungsseite bearbeiten können.",
|
||||
"company_logo": "Firmenlogo",
|
||||
"company_name": "Firmenname",
|
||||
"confirm_password": "Passwort bestätigen",
|
||||
"continue": "Weiter",
|
||||
"country": "Land",
|
||||
"currency": "Currency",
|
||||
"database": {
|
||||
"app_url": "App-URL",
|
||||
"connection": "Datenbank Verbindung",
|
||||
"database": "URL der Seite & Datenbank",
|
||||
"db_name": "Datenbank Name",
|
||||
"desc": "Erstellen Sie eine Datenbank auf Ihrem Server und legen Sie die Anmeldeinformationen mithilfe des folgenden Formulars fest.",
|
||||
"host": "Datenbank Host",
|
||||
"password": "Datenbank Passwort",
|
||||
"port": "Datenbank Port",
|
||||
"username": "Datenbank Benutzername"
|
||||
},
|
||||
"date_format": "Datumsformat",
|
||||
"email": "Email",
|
||||
"errors": {
|
||||
"connection_failed": "Datenbankverbindung fehlgeschlagen",
|
||||
"database_should_be_empty": "Datenbank sollte leer sein",
|
||||
"database_variables_save_error": "Konfiguration kann nicht in EN.env-Datei geschrieben werden. Bitte überprüfen Sie die Dateiberechtigungen.",
|
||||
"mail_variables_save_error": "E-Mail-Konfiguration fehlgeschlagen.",
|
||||
"migrate_failed": "Migration ist Fehlgeschlagen"
|
||||
},
|
||||
"fiscal_year": "Geschäftsjahr",
|
||||
"from_address": "From Address",
|
||||
"go_back": "Zurück",
|
||||
"language": "Sprache",
|
||||
"logo_preview": "Vorschau Logo",
|
||||
"mail": {
|
||||
"driver": "E-Mail-Treiber",
|
||||
"encryption": "E-Mail-Verschlüsselung",
|
||||
"from_mail": "Von E-Mail-Absenderadresse",
|
||||
"from_name": "Von E-Mail-Absendername",
|
||||
"host": "E-Mail-Host",
|
||||
"mail_config": "E-Mail-Konfiguration",
|
||||
"mail_config_desc": "Unten finden Sie das Formular zum Konfigurieren des E-Mail-Treibers zum Senden von E-Mails über die App. Sie können auch Drittanbieter wie Sendgrid, SES usw. konfigurieren.",
|
||||
"mailgun_domain": "Domain",
|
||||
"mailgun_endpoint": "Mailgun-Endpunkt",
|
||||
"mailgun_secret": "Mailgun Verschlüsselung",
|
||||
"password": "E-Mail-Passwort",
|
||||
"port": "E-Mail-Port",
|
||||
"secret": "Verschlüsselung",
|
||||
"ses_key": "SES-Taste",
|
||||
"ses_secret": "SES Verschlüsselung",
|
||||
"username": "E-Mail-Benutzername"
|
||||
},
|
||||
"name": "Name",
|
||||
"next": "Next",
|
||||
"password": "Passwort",
|
||||
"permissions": {
|
||||
"permission_confirm_desc": "Prüfung der Berechtigung der Ordner fehlgeschlagen.",
|
||||
"permission_confirm_title": "Sind Sie sicher, dass Sie fortfahren möchten?",
|
||||
"permission_desc": "Unten finden Sie eine Liste der Ordnerberechtigungen, die erforderlich sind, damit die App funktioniert. Wenn die Berechtigungsprüfung fehlschlägt, müssen Sie Ihre Ordnerberechtigungen aktualisieren.",
|
||||
"permissions": "Berechtigungen"
|
||||
},
|
||||
"phone": "Telefon",
|
||||
"preferences": "Einstellungen",
|
||||
"preferences_desc": "Standardeinstellungen für das System.",
|
||||
"req": {
|
||||
"check_req": "Anforderungen prüfen",
|
||||
"php_req_version": "Php (version {version} erforderlich)",
|
||||
"system_req": "System Anforderungen",
|
||||
"system_req_desc": "Crater hat einige Serveranforderungen. Stellen Sie sicher, dass Ihr Server die erforderliche PHP-Version und alle unten genannten Erweiterungen hat."
|
||||
},
|
||||
"save_cont": "Speichern und weiter",
|
||||
"skip": "Überspringen",
|
||||
"state": "Bundesland",
|
||||
"street": "Straße1 | Straße2",
|
||||
"success": {
|
||||
"database_variables_save_successfully": "Datenbank erfolgreich konfiguriert.",
|
||||
"mail_variables_save_successfully": "E-Mail erfolgreich konfiguriert"
|
||||
},
|
||||
"time_zone": "Zeitzone",
|
||||
"username": "Benutzername",
|
||||
"zip_code": "Postleitzahl"
|
||||
}
|
||||
}
|
||||
@ -17,11 +17,17 @@
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"update": "Update",
|
||||
"deselect": "Deselect",
|
||||
"download": "Download",
|
||||
"from_date": "From Date",
|
||||
"to_date": "To Date",
|
||||
"from": "From",
|
||||
"to": "To",
|
||||
"sort_by": "Sort By",
|
||||
"ascending": "Ascending",
|
||||
"descending": "Descending",
|
||||
"subject": "Subject",
|
||||
"message": "Message",
|
||||
"go_back": "Go Back",
|
||||
"back_to_login": "Back to Login?",
|
||||
"home": "Home",
|
||||
@ -62,6 +68,8 @@
|
||||
"four_zero_four": "404",
|
||||
"you_got_lost": "Whoops! You got Lost!",
|
||||
"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",
|
||||
@ -180,7 +188,7 @@
|
||||
"no_items": "No items yet!",
|
||||
"list_of_items": "This section will contain the list of items.",
|
||||
"select_a_unit": "select unit",
|
||||
|
||||
"taxes": "Taxes",
|
||||
"item_attached_message": "Cannot delete an item which is already in use",
|
||||
"confirm_delete": "You will not be able to recover this Item | You will not be able to recover these Items",
|
||||
"created_message": "Item created successfully",
|
||||
@ -225,7 +233,7 @@
|
||||
"record_payment": "Record Payment",
|
||||
"add_estimate": "Add Estimate",
|
||||
"save_estimate": "Save Estimate",
|
||||
"confirm_conversion": "You want to convert this Estimate into Invoice?",
|
||||
"confirm_conversion": "This estimate will be used to create a new Invoice.",
|
||||
"conversion_message": "Invoice created successful",
|
||||
"confirm_send_estimate": "This estimate will be sent via email to the customer",
|
||||
"confirm_mark_as_sent": "This estimate will be marked as sent",
|
||||
@ -329,6 +337,9 @@
|
||||
"no_matching_invoices": "There are no matching invoices!",
|
||||
"mark_as_sent_successfully": "Invoice marked as sent successfully",
|
||||
"send_invoice_successfully": "Invoice sent successfully",
|
||||
"cloned_successfully": "Invoice cloned successfully",
|
||||
"clone_invoice": "Clone Invoice",
|
||||
"confirm_clone": "This invoice will be cloned into a new Invoice",
|
||||
"item": {
|
||||
"title": "Item Title",
|
||||
"description": "Description",
|
||||
@ -394,12 +405,17 @@
|
||||
"edit_payment": "Edit Payment",
|
||||
"view_payment": "View Payment",
|
||||
"add_new_payment": "Add New Payment",
|
||||
"send_payment_receipt": "Send Payment Receipt",
|
||||
"save_payment": "Save Payment",
|
||||
"update_payment": "Update Payment",
|
||||
"payment": "Payment | Payments",
|
||||
"no_payments": "No payments yet!",
|
||||
"list_of_payments": "This section will contain the list of payments.",
|
||||
"select_payment_mode": "Select payment mode",
|
||||
"confirm_send_payment": "This payment will be sent via email to the customer",
|
||||
"send_payment_successfully": "Payment sent successfully",
|
||||
"user_email_does_not_exist": "User email does not exist",
|
||||
"something_went_wrong": "something went wrong",
|
||||
|
||||
"confirm_delete": "You will not be able to recover this Payment | You will not be able to recover these Payments",
|
||||
"created_message": "Payment created successfully",
|
||||
@ -633,7 +649,7 @@
|
||||
"notes": "Notes",
|
||||
"invoice_prefix": "Invoice Prefix",
|
||||
"invoice_settings": "Invoice Settings",
|
||||
"autogenerate_invoice_number": "Autogenerate Invoice Number",
|
||||
"autogenerate_invoice_number": "Auto-generate Invoice Number",
|
||||
"invoice_setting_description": "Disable this, If you don't wish to auto-generate invoice numbers each time you create a new invoice.",
|
||||
"enter_invoice_prefix": "Enter invoice prefix",
|
||||
"terms_and_conditions": "Terms and Conditions",
|
||||
@ -644,7 +660,7 @@
|
||||
"title": "Estimates",
|
||||
"estimate_prefix": "Estimate Prefix",
|
||||
"estimate_settings": "Estimate Settings",
|
||||
"autogenerate_estimate_number": "Autogenerate Estimate Number",
|
||||
"autogenerate_estimate_number": "Auto-generate Estimate Number",
|
||||
"estimate_setting_description": "Disable this, If you don't wish to auto-generate estimate numbers each time you create a new estimate.",
|
||||
"enter_estimate_prefix": "Enter estmiate prefix",
|
||||
"estimate_setting_updated": "Estimate Setting updated successfully"
|
||||
@ -654,10 +670,30 @@
|
||||
"title": "Payments",
|
||||
"payment_prefix": "Payment Prefix",
|
||||
"payment_settings": "Payment Settings",
|
||||
"autogenerate_payment_number": "Autogenerate Payment Number",
|
||||
"autogenerate_payment_number": "Auto-generate Payment Number",
|
||||
"payment_setting_description": "Disable this, If you don't wish to auto-generate payment numbers each time you create a new payment.",
|
||||
"enter_payment_prefix": "Enter Payment Prefix",
|
||||
"payment_setting_updated": "Payment Setting updated successfully"
|
||||
"payment_setting_updated": "Payment Setting updated successfully",
|
||||
"payment_mode": "Payment Mode",
|
||||
"add_payment_mode": "Add Payment Mode",
|
||||
"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",
|
||||
"already_in_use": "Payment Mode is already in use",
|
||||
"deleted_message": "Payment Mode deleted successfully"
|
||||
},
|
||||
|
||||
"items": {
|
||||
"title": "Items",
|
||||
"units": "units",
|
||||
"add_item_unit": "Add Item Unit",
|
||||
"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",
|
||||
"already_in_use": "Item Unit is already in use",
|
||||
"deleted_message": "Item Unit deleted successfully"
|
||||
}
|
||||
},
|
||||
"account_settings": {
|
||||
@ -852,6 +888,8 @@
|
||||
"email_incorrect": "Incorrect Email.",
|
||||
"email_already_taken": "The email has already been taken.",
|
||||
"email_does_not_exist": "User with given email doesn't exist",
|
||||
"item_unit_already_taken": "This item unit name has already been taken",
|
||||
"payment_mode_already_taken": "This payment mode name has already been taken",
|
||||
"send_reset_link": "Send Reset Link",
|
||||
"not_yet": "Not yet? Send it again",
|
||||
"password_min_length": "Password must contain {count} characters",
|
||||
@ -871,10 +909,13 @@
|
||||
"amount_maxlength": "Amount should not be greater than 20 digits.",
|
||||
"amount_minvalue": "Amount should be greater than 0.",
|
||||
"description_maxlength": "Description should not be greater than 255 characters.",
|
||||
"subject_maxlength": "Subject should not be greater than 100 characters.",
|
||||
"message_maxlength": "Message should not be greater than 255 characters.",
|
||||
"maximum_options_error": "Maximum of {max} options selected. First remove a selected option to select another.",
|
||||
"notes_maxlength": "Notes should not be greater than 255 characters.",
|
||||
"address_maxlength": "Address should not be greater than 255 characters.",
|
||||
"ref_number_maxlength": "Ref Number should not be greater than 255 characters.",
|
||||
"prefix_maxlength": "Prefix should not be greater than 5 characters."
|
||||
"prefix_maxlength": "Prefix should not be greater than 5 characters.",
|
||||
"something_went_wrong": "something went wrong"
|
||||
}
|
||||
}
|
||||
|
||||
@ -784,6 +784,8 @@
|
||||
"required": "Se requiere campo",
|
||||
"email_incorrect": "Email incorrecto.",
|
||||
"email_does_not_exist": " Usuario con correo electrónico dado no existe",
|
||||
"item_unit_already_taken": "La unidad del artículo ya ha sido tomada",
|
||||
"payment_mode_already_taken": "El modo de pago ya ha sido tomado",
|
||||
"send_reset_link": "Enviar restablecer enlace",
|
||||
"not_yet": "¿Aún no? Envialo de nuevo",
|
||||
"password_min_length": "La contraseña debe contener {count} caracteres",
|
||||
|
||||
@ -787,6 +787,8 @@
|
||||
"required": "Champ requis",
|
||||
"email_incorrect": "Adresse Email incorrecte.",
|
||||
"email_does_not_exist": "L'utilisateur avec un email donné n'existe pas",
|
||||
"item_unit_already_taken": "L'unité d'article a déjà été prise",
|
||||
"payment_mode_already_taken": "Le mode de paiement a déjà été pris",
|
||||
"send_reset_link": "Envoyer le lien de réinitialisation",
|
||||
"not_yet": "Pas encore? Envoyer à nouveau",
|
||||
"password_min_length": "Le mot de passe doit contenir {nombre} caractères",
|
||||
|
||||
@ -4,6 +4,7 @@ import en from './en.json'
|
||||
import fr from './fr.json'
|
||||
import es from './es.json'
|
||||
import ar from './ar.json'
|
||||
import de from './de.json'
|
||||
|
||||
Vue.use(VueI18n)
|
||||
|
||||
@ -13,7 +14,8 @@ const i18n = new VueI18n({
|
||||
en,
|
||||
fr,
|
||||
es,
|
||||
ar
|
||||
ar,
|
||||
de
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@ -46,6 +46,7 @@ import InvoiceView from './views/invoices/View.vue'
|
||||
// Payments
|
||||
import PaymentsIndex from './views/payments/Index.vue'
|
||||
import PaymentCreate from './views/payments/Create.vue'
|
||||
import PaymentView from './views/payments/View.vue'
|
||||
|
||||
// Estimates
|
||||
import EstimateIndex from './views/estimates/Index.vue'
|
||||
@ -259,6 +260,11 @@ const routes = [
|
||||
name: 'payments.edit',
|
||||
component: PaymentCreate
|
||||
},
|
||||
{
|
||||
path: 'payments/:id/view',
|
||||
name: 'payments.view',
|
||||
component: PaymentView
|
||||
},
|
||||
|
||||
// Expenses
|
||||
{
|
||||
|
||||
@ -4,6 +4,8 @@ import * as userTypes from './modules/user/mutation-types'
|
||||
import * as companyTypes from './modules/company/mutation-types'
|
||||
import * as preferencesTypes from './modules/settings/preferences/mutation-types'
|
||||
import * as taxTypeTypes from './modules/tax-type/mutation-types'
|
||||
import * as itemTypes from './modules/item/mutation-types'
|
||||
import * as paymentModes from './modules/payment/mutation-types'
|
||||
|
||||
export default {
|
||||
bootstrap ({ commit, dispatch, state }) {
|
||||
@ -17,6 +19,8 @@ export default {
|
||||
commit('taxType/' + taxTypeTypes.BOOTSTRAP_TAX_TYPES, response.data.taxTypes)
|
||||
commit('preferences/' + preferencesTypes.SET_MOMENT_DATE_FORMAT, response.data.moment_date_format)
|
||||
commit('preferences/' + preferencesTypes.SET_LANGUAGE_FORMAT, response.data.default_language)
|
||||
commit('item/' + itemTypes.SET_ITEM_UNITS, response.data.units)
|
||||
commit('payment/' + paymentModes.SET_PAYMENT_MODES, response.data.paymentMethods)
|
||||
commit(types.UPDATE_APP_LOADING_STATUS, true)
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
|
||||
@ -135,6 +135,16 @@ export const markAsSent = ({ commit, dispatch, state }, data) => {
|
||||
})
|
||||
}
|
||||
|
||||
export const cloneInvoice = ({ commit, dispatch, state }, data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.post(`/api/invoices/clone`, data).then((response) => {
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const searchInvoice = ({ commit, dispatch, state }, data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.get(`/api/invoices?${data}`).then((response) => {
|
||||
|
||||
@ -26,7 +26,6 @@ export const addItem = ({ commit, dispatch, state }, data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.post('/api/items', data).then((response) => {
|
||||
commit(types.ADD_ITEM, response.data)
|
||||
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
@ -90,3 +89,57 @@ export const selectItem = ({ commit, dispatch, state }, data) => {
|
||||
commit(types.SET_SELECT_ALL_STATE, false)
|
||||
}
|
||||
}
|
||||
|
||||
export const addItemUnit = ({ commit, dispatch, state }, data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.post(`/api/units`, data).then((response) => {
|
||||
commit(types.ADD_ITEM_UNIT, response.data)
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const updateItemUnit = ({ commit, dispatch, state }, data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.put(`/api/units/${data.id}`, data).then((response) => {
|
||||
commit(types.UPDATE_ITEM_UNIT, response.data)
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchItemUnits = ({ commit, dispatch, state }) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.get(`/api/units`).then((response) => {
|
||||
commit(types.SET_ITEM_UNITS, response.data.units)
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const fatchItemUnit = ({ commit, dispatch, state }, id) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.get(`/api/units/${id}`).then((response) => {
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const deleteItemUnit = ({ commit, dispatch, state }, id) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.delete(`/api/units/${id}`).then((response) => {
|
||||
commit(types.DELETE_ITEM_UNIT, id)
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -2,3 +2,4 @@ export const items = (state) => state.items
|
||||
export const selectAllField = (state) => state.selectAllField
|
||||
export const selectedItems = (state) => state.selectedItems
|
||||
export const totalItems = (state) => state.totalItems
|
||||
export const itemUnits = (state) => state.itemUnits
|
||||
|
||||
@ -6,7 +6,8 @@ const initialState = {
|
||||
items: [],
|
||||
totalItems: 0,
|
||||
selectAllField: false,
|
||||
selectedItems: []
|
||||
selectedItems: [],
|
||||
itemUnits: []
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@ -6,3 +6,7 @@ export const DELETE_MULTIPLE_ITEMS = 'DELETE_MULTIPLE_ITEMS'
|
||||
export const SET_SELECTED_ITEMS = 'SET_SELECTED_ITEMS'
|
||||
export const SET_TOTAL_ITEMS = 'SET_TOTAL_ITEMS'
|
||||
export const SET_SELECT_ALL_STATE = 'SET_SELECT_ALL_STATE'
|
||||
export const ADD_ITEM_UNIT = 'ADD_ITEM_UNIT'
|
||||
export const SET_ITEM_UNITS = 'SET_ITEM_UNITS'
|
||||
export const UPDATE_ITEM_UNIT = 'UPDATE_ITEM_UNIT'
|
||||
export const DELETE_ITEM_UNIT = 'DELETE_ITEM_UNIT'
|
||||
|
||||
@ -39,6 +39,25 @@ export default {
|
||||
|
||||
[types.SET_SELECT_ALL_STATE] (state, data) {
|
||||
state.selectAllField = data
|
||||
}
|
||||
},
|
||||
|
||||
[types.ADD_ITEM_UNIT] (state, data) {
|
||||
state.itemUnits.push(data.unit)
|
||||
state.itemUnits = [data.unit, ...state.itemUnits]
|
||||
},
|
||||
|
||||
[types.SET_ITEM_UNITS] (state, data) {
|
||||
state.itemUnits = data
|
||||
},
|
||||
|
||||
[types.DELETE_ITEM_UNIT] (state, id) {
|
||||
let index = state.itemUnits.findIndex(unit => unit.id === id)
|
||||
state.itemUnits.splice(index, 1)
|
||||
},
|
||||
|
||||
[types.UPDATE_ITEM_UNIT] (state, data) {
|
||||
let pos = state.itemUnits.findIndex(unit => unit.id === data.unit.id)
|
||||
state.itemUnits.splice(pos, 1)
|
||||
state.itemUnits = [data.unit, ...state.itemUnits]
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,9 +12,9 @@ export const fetchPayments = ({ commit, dispatch, state }, params) => {
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchCreatePayment = ({ commit, dispatch }, page) => {
|
||||
export const fetchPayment = ({ commit, dispatch }, id) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.get(`/api/payments/create`).then((response) => {
|
||||
window.axios.get(`/api/payments/${id}`).then((response) => {
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
@ -22,7 +22,7 @@ export const fetchCreatePayment = ({ commit, dispatch }, page) => {
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchPayment = ({ commit, dispatch }, id) => {
|
||||
export const fetchEditPaymentData = ({ commit, dispatch }, id) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.get(`/api/payments/${id}/edit`).then((response) => {
|
||||
resolve(response)
|
||||
@ -32,6 +32,16 @@ export const fetchPayment = ({ commit, dispatch }, id) => {
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchCreatePayment = ({ commit, dispatch }, page) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.get(`/api/payments/create`).then((response) => {
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const addPayment = ({ commit, dispatch, state }, data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.post('/api/payments', data).then((response) => {
|
||||
@ -97,3 +107,78 @@ export const selectAllPayments = ({ commit, dispatch, state }) => {
|
||||
commit(types.SET_SELECT_ALL_STATE, true)
|
||||
}
|
||||
}
|
||||
|
||||
export const addPaymentMode = ({ commit, dispatch, state }, data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.post(`/api/payment-methods`, data).then((response) => {
|
||||
commit(types.ADD_PAYMENT_MODE, response.data)
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const updatePaymentMode = ({ commit, dispatch, state }, data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.put(`/api/payment-methods/${data.id}`, data).then((response) => {
|
||||
commit(types.UPDATE_PAYMENT_MODE, response.data)
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchPaymentModes = ({ commit, dispatch, state }, data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.get(`/api/payment-methods`, data).then((response) => {
|
||||
commit(types.SET_PAYMENT_MODES, response.data.paymentMethods)
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchPaymentMode = ({ commit, dispatch, state }, data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.get(`/api/payment-methods/${data.id}`, data).then((response) => {
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const deletePaymentMode = ({ commit, dispatch, state }, id) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.delete(`/api/payment-methods/${id}`).then((response) => {
|
||||
commit(types.DELETE_PAYMENT_MODE, id)
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const sendEmail = ({ commit, dispatch, state }, data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.post(`/api/payments/send`, data).then((response) => {
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const searchPayment = ({ commit, dispatch, state }, data) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.axios.get(`/api/payments?${data}`).then((response) => {
|
||||
// commit(types.UPDATE_INVOICE, response.data)
|
||||
resolve(response)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -2,3 +2,4 @@ export const payments = (state) => state.payments
|
||||
export const selectedPayments = (state) => state.selectedPayments
|
||||
export const selectAllField = (state) => state.selectAllField
|
||||
export const totalPayments = (state) => state.totalPayments
|
||||
export const paymentModes = (state) => state.paymentModes
|
||||
|
||||
@ -6,7 +6,8 @@ const initialState = {
|
||||
payments: [],
|
||||
totalPayments: 0,
|
||||
selectAllField: false,
|
||||
selectedPayments: []
|
||||
selectedPayments: [],
|
||||
paymentModes: []
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@ -6,3 +6,7 @@ export const DELETE_MULTIPLE_PAYMENTS = 'DELETE_MULTIPLE_PAYMENTS'
|
||||
export const SET_SELECTED_PAYMENTS = 'SET_SELECTED_PAYMENTS'
|
||||
export const SET_TOTAL_PAYMENTS = 'SET_TOTAL_PAYMENTS'
|
||||
export const SET_SELECT_ALL_STATE = 'SET_SELECT_ALL_STATE'
|
||||
export const ADD_PAYMENT_MODE = 'ADD_PAYMENT_MODE'
|
||||
export const DELETE_PAYMENT_MODE = 'DELETE_PAYMENT_MODE'
|
||||
export const SET_PAYMENT_MODES = 'SET_PAYMENT_MODES'
|
||||
export const UPDATE_PAYMENT_MODE = 'UPDATE_PAYMENT_MODE'
|
||||
|
||||
@ -33,5 +33,25 @@ export default {
|
||||
|
||||
[types.SET_SELECT_ALL_STATE] (state, data) {
|
||||
state.selectAllField = data
|
||||
},
|
||||
|
||||
[types.SET_PAYMENT_MODES] (state, data) {
|
||||
state.paymentModes = data
|
||||
},
|
||||
|
||||
[types.ADD_PAYMENT_MODE] (state, data) {
|
||||
state.paymentModes.push(data.paymentMethod)
|
||||
state.paymentModes = [data.paymentMethod, ...state.paymentModes]
|
||||
},
|
||||
|
||||
[types.DELETE_PAYMENT_MODE] (state, id) {
|
||||
let index = state.paymentModes.findIndex(paymentMethod => paymentMethod.id === id)
|
||||
state.paymentModes.splice(index, 1)
|
||||
},
|
||||
|
||||
[types.UPDATE_PAYMENT_MODE] (state, data) {
|
||||
let pos = state.paymentModes.findIndex(paymentMethod => paymentMethod.id === data.paymentMethod.id)
|
||||
state.paymentModes.splice(pos, 1)
|
||||
state.paymentModes = [data.paymentMethod, ...state.paymentModes]
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +85,8 @@
|
||||
</div>
|
||||
<div class="customer-content mb-1">
|
||||
<label class="email">{{ selectedCustomer.name }}</label>
|
||||
<label class="action" @click="removeCustomer">{{ $t('general.remove') }}</label>
|
||||
<label class="action" @click="editCustomer">{{ $t('general.edit') }}</label>
|
||||
<label class="action" @click="removeCustomer">{{ $t('general.deselect') }}</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -195,6 +196,7 @@
|
||||
:index="index"
|
||||
:item-data="item"
|
||||
:currency="currency"
|
||||
:estimate-items="newEstimate.items"
|
||||
:tax-per-item="taxPerItem"
|
||||
:discount-per-item="discountPerItem"
|
||||
@remove="removeItem"
|
||||
@ -589,6 +591,14 @@ export default {
|
||||
removeCustomer () {
|
||||
this.resetSelectedCustomer()
|
||||
},
|
||||
editCustomer () {
|
||||
this.openModal({
|
||||
'title': this.$t('customers.edit_customer'),
|
||||
'componentName': 'CustomerModal',
|
||||
'id': this.selectedCustomer.id,
|
||||
'data': this.selectedCustomer
|
||||
})
|
||||
},
|
||||
openTemplateModal () {
|
||||
this.openModal({
|
||||
'title': this.$t('general.choose_template'),
|
||||
|
||||
@ -24,6 +24,8 @@
|
||||
:invalid="$v.item.name.$error"
|
||||
:invalid-description="$v.item.description.$error"
|
||||
:item="item"
|
||||
:tax-per-item="taxPerItem"
|
||||
:taxes="item.taxes"
|
||||
@search="searchVal"
|
||||
@select="onSelectItem"
|
||||
@deselect="deselectItem"
|
||||
@ -108,7 +110,7 @@
|
||||
|
||||
<div class="remove-icon-wrapper">
|
||||
<font-awesome-icon
|
||||
v-if="index > 0"
|
||||
v-if="isShowRemoveItemIcon"
|
||||
class="remove-icon"
|
||||
icon="trash-alt"
|
||||
@click="removeItem"
|
||||
@ -180,6 +182,10 @@ export default {
|
||||
discountPerItem: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
estimateItems: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@ -221,6 +227,12 @@ export default {
|
||||
return this.defaultCurrencyForInput
|
||||
}
|
||||
},
|
||||
isShowRemoveItemIcon () {
|
||||
if (this.estimateItems.length == 1) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
subtotal () {
|
||||
return this.item.price * this.item.quantity
|
||||
},
|
||||
@ -324,6 +336,9 @@ export default {
|
||||
created () {
|
||||
window.hub.$on('checkItems', this.validateItem)
|
||||
window.hub.$on('newItem', (val) => {
|
||||
if (this.taxPerItem === 'YES') {
|
||||
this.item.taxes = val.taxes
|
||||
}
|
||||
if (!this.item.item_id && this.modalActive && this.isSelected) {
|
||||
this.onSelectItem(val)
|
||||
}
|
||||
@ -363,7 +378,13 @@ export default {
|
||||
this.item.price = item.price
|
||||
this.item.item_id = item.id
|
||||
this.item.description = item.description
|
||||
|
||||
if (this.taxPerItem === 'YES' && item.taxes) {
|
||||
let index = 0
|
||||
item.taxes.forEach(tax => {
|
||||
this.updateTax({index, item: { ...tax }})
|
||||
index++
|
||||
})
|
||||
}
|
||||
// if (this.item.taxes.length) {
|
||||
// this.item.taxes = {...item.taxes}
|
||||
// }
|
||||
|
||||
@ -68,6 +68,14 @@ export default {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
taxPerItem: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
taxes: {
|
||||
type: Array,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@ -129,7 +137,8 @@ export default {
|
||||
this.$emit('onSelectItem')
|
||||
this.openModal({
|
||||
'title': 'Add Item',
|
||||
'componentName': 'ItemModal'
|
||||
'componentName': 'ItemModal',
|
||||
'data': {taxPerItem: this.taxPerItem, taxes: this.taxes}
|
||||
})
|
||||
},
|
||||
deselectItem () {
|
||||
|
||||
@ -69,7 +69,9 @@
|
||||
<font-awesome-icon icon="filter" />
|
||||
</base-button>
|
||||
</a>
|
||||
|
||||
<div class="filter-title">
|
||||
{{ $t('general.sort_by') }}
|
||||
</div>
|
||||
<div class="filter-items">
|
||||
<input
|
||||
id="filter_estimate_date"
|
||||
@ -107,7 +109,7 @@
|
||||
<label class="inv-label" for="filter_estimate_number">{{ $t('estimates.estimate_number') }}</label>
|
||||
</div>
|
||||
</v-dropdown>
|
||||
<base-button 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>
|
||||
@ -172,7 +174,12 @@ export default {
|
||||
}
|
||||
return false
|
||||
},
|
||||
|
||||
getOrderName () {
|
||||
if (this.getOrderBy) {
|
||||
return this.$t('general.ascending')
|
||||
}
|
||||
return this.$t('general.descending')
|
||||
},
|
||||
shareableLink () {
|
||||
return `/estimates/pdf/${this.estimate.unique_hash}`
|
||||
}
|
||||
|
||||
@ -83,7 +83,8 @@
|
||||
</div>
|
||||
<div class="customer-content mb-1">
|
||||
<label class="email">{{ selectedCustomer.name }}</label>
|
||||
<label class="action" @click="removeCustomer">{{ $t('general.remove') }}</label>
|
||||
<label class="action" @click="editCustomer">{{ $t('general.edit') }}</label>
|
||||
<label class="action" @click="removeCustomer">{{ $t('general.deselect') }}</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -193,6 +194,7 @@
|
||||
:key="item.id"
|
||||
:index="index"
|
||||
:item-data="item"
|
||||
:invoice-items="newInvoice.items"
|
||||
:currency="currency"
|
||||
:tax-per-item="taxPerItem"
|
||||
:discount-per-item="discountPerItem"
|
||||
@ -589,6 +591,14 @@ export default {
|
||||
removeCustomer () {
|
||||
this.resetSelectedCustomer()
|
||||
},
|
||||
editCustomer () {
|
||||
this.openModal({
|
||||
'title': this.$t('customers.edit_customer'),
|
||||
'componentName': 'CustomerModal',
|
||||
'id': this.selectedCustomer.id,
|
||||
'data': this.selectedCustomer
|
||||
})
|
||||
},
|
||||
openTemplateModal () {
|
||||
this.openModal({
|
||||
'title': this.$t('general.choose_template'),
|
||||
|
||||
@ -259,6 +259,18 @@
|
||||
{{ $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"/>
|
||||
{{ $t('payments.record_payment') }}
|
||||
</router-link>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item>
|
||||
<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" />
|
||||
@ -378,7 +390,8 @@ export default {
|
||||
'deleteMultipleInvoices',
|
||||
'sendEmail',
|
||||
'markAsSent',
|
||||
'setSelectAllState'
|
||||
'setSelectAllState',
|
||||
'cloneInvoice'
|
||||
]),
|
||||
...mapActions('customer', [
|
||||
'fetchCustomers'
|
||||
@ -429,6 +442,27 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
async onCloneInvoice (id) {
|
||||
swal({
|
||||
title: this.$t('general.are_you_sure'),
|
||||
text: this.$t('invoices.confirm_clone'),
|
||||
icon: '/assets/icon/check-circle-solid.svg',
|
||||
buttons: true,
|
||||
dangerMode: true
|
||||
}).then(async (value) => {
|
||||
if (value) {
|
||||
const data = {
|
||||
id: id
|
||||
}
|
||||
let response = await this.cloneInvoice(data)
|
||||
this.refreshTable()
|
||||
if (response.data) {
|
||||
window.toastr['success'](this.$tc('invoices.cloned_successfully'))
|
||||
this.$router.push(`/admin/invoices/${response.data.invoice.id}/edit`)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
getStatus (val) {
|
||||
this.filters.status = {
|
||||
name: val,
|
||||
|
||||
@ -24,6 +24,8 @@
|
||||
:invalid="$v.item.name.$error"
|
||||
:invalid-description="$v.item.description.$error"
|
||||
:item="item"
|
||||
:tax-per-item="taxPerItem"
|
||||
:taxes="item.taxes"
|
||||
@search="searchVal"
|
||||
@select="onSelectItem"
|
||||
@deselect="deselectItem"
|
||||
@ -109,7 +111,7 @@
|
||||
|
||||
<div class="remove-icon-wrapper">
|
||||
<font-awesome-icon
|
||||
v-if="index > 0"
|
||||
v-if="showRemoveItemIcon"
|
||||
class="remove-icon"
|
||||
icon="trash-alt"
|
||||
@click="removeItem"
|
||||
@ -181,6 +183,10 @@ export default {
|
||||
discountPerItem: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
invoiceItems: {
|
||||
type: Array,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@ -222,6 +228,12 @@ export default {
|
||||
return this.defaultCurrenctForInput
|
||||
}
|
||||
},
|
||||
showRemoveItemIcon () {
|
||||
if (this.invoiceItems.length == 1) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
subtotal () {
|
||||
return this.item.price * this.item.quantity
|
||||
},
|
||||
@ -325,6 +337,9 @@ export default {
|
||||
created () {
|
||||
window.hub.$on('checkItems', this.validateItem)
|
||||
window.hub.$on('newItem', (val) => {
|
||||
if (this.taxPerItem === 'YES') {
|
||||
this.item.taxes = val.taxes
|
||||
}
|
||||
if (!this.item.item_id && this.modalActive && this.isSelected) {
|
||||
this.onSelectItem(val)
|
||||
}
|
||||
@ -364,7 +379,13 @@ export default {
|
||||
this.item.price = item.price
|
||||
this.item.item_id = item.id
|
||||
this.item.description = item.description
|
||||
|
||||
if (this.taxPerItem === 'YES' && item.taxes) {
|
||||
let index = 0
|
||||
item.taxes.forEach(tax => {
|
||||
this.updateTax({index, item: { ...tax }})
|
||||
index++
|
||||
})
|
||||
}
|
||||
// if (this.item.taxes.length) {
|
||||
// this.item.taxes = {...item.taxes}
|
||||
// }
|
||||
|
||||
@ -66,6 +66,14 @@ export default {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
taxPerItem: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
taxes: {
|
||||
type: Array,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@ -118,7 +126,8 @@ export default {
|
||||
this.$emit('onSelectItem')
|
||||
this.openModal({
|
||||
'title': 'Add Item',
|
||||
'componentName': 'ItemModal'
|
||||
'componentName': 'ItemModal',
|
||||
'data': {taxPerItem: this.taxPerItem, taxes: this.taxes}
|
||||
})
|
||||
},
|
||||
deselectItem () {
|
||||
|
||||
@ -73,7 +73,9 @@
|
||||
<font-awesome-icon icon="filter" />
|
||||
</base-button>
|
||||
</a>
|
||||
|
||||
<div class="filter-title">
|
||||
{{ $t('general.sort_by') }}
|
||||
</div>
|
||||
<div class="filter-items">
|
||||
<input
|
||||
id="filter_invoice_date"
|
||||
@ -111,7 +113,7 @@
|
||||
<label class="inv-label" for="filter_invoice_number">{{ $t('invoices.invoice_number') }}</label>
|
||||
</div>
|
||||
</v-dropdown>
|
||||
<base-button 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>
|
||||
@ -168,13 +170,18 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
getOrderBy () {
|
||||
if (this.searchData.orderBy === 'asc' || this.searchData.orderBy == null) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
getOrderName () {
|
||||
if (this.getOrderBy) {
|
||||
return this.$t('general.ascending')
|
||||
}
|
||||
return this.$t('general.descending')
|
||||
},
|
||||
shareableLink () {
|
||||
return `/invoices/pdf/${this.invoice.unique_hash}`
|
||||
}
|
||||
|
||||
@ -50,11 +50,31 @@
|
||||
<label>{{ $t('items.unit') }}</label>
|
||||
<base-select
|
||||
v-model="formData.unit"
|
||||
:options="units"
|
||||
:options="itemUnits"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('items.select_a_unit')"
|
||||
label="name"
|
||||
>
|
||||
<div slot="afterList">
|
||||
<button type="button" class="list-add-button" @click="addItemUnit">
|
||||
<font-awesome-icon class="icon" icon="cart-plus" />
|
||||
<label>{{ $t('settings.customization.items.add_item_unit') }}</label>
|
||||
</button>
|
||||
</div>
|
||||
</base-select>
|
||||
</div>
|
||||
<div v-if="isTaxPerItem" class="form-group">
|
||||
<label>{{ $t('items.taxes') }}</label>
|
||||
<base-select
|
||||
v-model="formData.taxes"
|
||||
:options="getTaxTypes"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:allow-empty="true"
|
||||
:multiple="true"
|
||||
track-by="tax_type_id"
|
||||
label="tax_name"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@ -66,7 +86,9 @@
|
||||
@input="$v.formData.description.$touch()"
|
||||
/>
|
||||
<div v-if="$v.formData.description.$error">
|
||||
<span v-if="!$v.formData.description.maxLength" class="text-danger">{{ $t('validation.description_maxlength') }}</span>
|
||||
<span v-if="!$v.formData.description.maxLength" class="text-danger">
|
||||
{{ $t('validation.description_maxlength') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@ -102,24 +124,17 @@ export default {
|
||||
return {
|
||||
isLoading: false,
|
||||
title: 'Add Item',
|
||||
units: [
|
||||
{ name: 'box', value: 'box' },
|
||||
{ name: 'cm', value: 'cm' },
|
||||
{ name: 'dz', value: 'dz' },
|
||||
{ name: 'ft', value: 'ft' },
|
||||
{ name: 'g', value: 'g' },
|
||||
{ name: 'in', value: 'in' },
|
||||
{ name: 'kg', value: 'kg' },
|
||||
{ name: 'km', value: 'km' },
|
||||
{ name: 'lb', value: 'lb' },
|
||||
{ name: 'mg', value: 'mg' },
|
||||
{ name: 'pc', value: 'pc' }
|
||||
],
|
||||
units: [],
|
||||
taxes: [],
|
||||
taxPerItem: '',
|
||||
formData: {
|
||||
name: '',
|
||||
description: '',
|
||||
price: '',
|
||||
unit: null
|
||||
unit_id: null,
|
||||
unit: null,
|
||||
taxes: [],
|
||||
tax_per_item: false
|
||||
},
|
||||
money: {
|
||||
decimal: '.',
|
||||
@ -134,6 +149,9 @@ export default {
|
||||
...mapGetters('currency', [
|
||||
'defaultCurrencyForInput'
|
||||
]),
|
||||
...mapGetters('item', [
|
||||
'itemUnits'
|
||||
]),
|
||||
price: {
|
||||
get: function () {
|
||||
return this.formData.price / 100
|
||||
@ -142,14 +160,26 @@ export default {
|
||||
this.formData.price = newValue * 100
|
||||
}
|
||||
},
|
||||
...mapGetters('taxType', [
|
||||
'taxTypes'
|
||||
]),
|
||||
isEdit () {
|
||||
if (this.$route.name === 'items.edit') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
isTaxPerItem () {
|
||||
return this.taxPerItem === 'YES' ? 1 : 0
|
||||
},
|
||||
getTaxTypes () {
|
||||
return this.taxTypes.map(tax => {
|
||||
return {...tax, tax_type_id: tax.id, tax_name: tax.name + ' (' + tax.percent + '%)'}
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.setTaxPerItem()
|
||||
if (this.isEdit) {
|
||||
this.loadEditData()
|
||||
}
|
||||
@ -177,10 +207,26 @@ export default {
|
||||
'fetchItem',
|
||||
'updateItem'
|
||||
]),
|
||||
...mapActions('modal', [
|
||||
'openModal'
|
||||
]),
|
||||
async setTaxPerItem () {
|
||||
let res = await axios.get('/api/settings/get-setting?key=tax_per_item')
|
||||
if (res.data && res.data.tax_per_item === 'YES') {
|
||||
this.taxPerItem = 'YES'
|
||||
} else {
|
||||
this.taxPerItem = 'FALSE'
|
||||
}
|
||||
},
|
||||
async loadEditData () {
|
||||
let response = await this.fetchItem(this.$route.params.id)
|
||||
this.formData = response.data.item
|
||||
this.formData.unit = this.units.find(_unit => response.data.item.unit === _unit.name)
|
||||
|
||||
this.formData = {...response.data.item, unit: null}
|
||||
this.formData.taxes = response.data.item.taxes.map(tax => {
|
||||
return {...tax, tax_name: tax.name + ' (' + tax.percent + '%)'}
|
||||
})
|
||||
|
||||
this.formData.unit = this.itemUnits.find(_unit => response.data.item.unit_id === _unit.id)
|
||||
this.fractional_price = response.data.item.price
|
||||
},
|
||||
async submitItem () {
|
||||
@ -189,30 +235,40 @@ export default {
|
||||
return false
|
||||
}
|
||||
if (this.formData.unit) {
|
||||
this.formData.unit = this.formData.unit.name
|
||||
this.formData.unit_id = this.formData.unit.id
|
||||
}
|
||||
let response
|
||||
if (this.isEdit) {
|
||||
this.isLoading = true
|
||||
let response = await this.updateItem(this.formData)
|
||||
if (response.data) {
|
||||
this.isLoading = false
|
||||
window.toastr['success'](this.$tc('items.updated_message'))
|
||||
this.$router.push('/admin/items')
|
||||
return true
|
||||
}
|
||||
window.toastr['error'](response.data.error)
|
||||
response = await this.updateItem(this.formData)
|
||||
} else {
|
||||
this.isLoading = true
|
||||
let response = await this.addItem(this.formData)
|
||||
|
||||
if (response.data) {
|
||||
window.toastr['success'](this.$tc('items.created_message'))
|
||||
this.$router.push('/admin/items')
|
||||
this.isLoading = false
|
||||
return true
|
||||
let data = {
|
||||
...this.formData,
|
||||
taxes: this.formData.taxes.map(tax => {
|
||||
return {
|
||||
tax_type_id: tax.id,
|
||||
amount: ((this.formData.price * tax.percent) / 100),
|
||||
percent: tax.percent,
|
||||
name: tax.name,
|
||||
collective_tax: 0
|
||||
}
|
||||
})
|
||||
}
|
||||
window.toastr['success'](response.data.success)
|
||||
response = await this.addItem(data)
|
||||
}
|
||||
if (response.data) {
|
||||
this.isLoading = false
|
||||
window.toastr['success'](this.$tc('items.updated_message'))
|
||||
this.$router.push('/admin/items')
|
||||
return true
|
||||
}
|
||||
window.toastr['error'](response.data.error)
|
||||
},
|
||||
async addItemUnit () {
|
||||
this.openModal({
|
||||
'title': 'Add Item Unit',
|
||||
'componentName': 'ItemUnit'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@
|
||||
<label class="form-label"> {{ $tc('items.unit') }} </label>
|
||||
<base-select
|
||||
v-model="filters.unit"
|
||||
:options="units"
|
||||
:options="itemUnits"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('items.select_a_unit')"
|
||||
@ -169,7 +169,7 @@
|
||||
/>
|
||||
<table-column
|
||||
:label="$t('items.unit')"
|
||||
show="unit"
|
||||
show="unit_name"
|
||||
/>
|
||||
<table-column
|
||||
:label="$t('items.price')"
|
||||
@ -235,19 +235,6 @@ export default {
|
||||
id: null,
|
||||
showFilters: false,
|
||||
sortedBy: 'created_at',
|
||||
units: [
|
||||
{ name: 'box', value: 'box' },
|
||||
{ name: 'cm', value: 'cm' },
|
||||
{ name: 'dz', value: 'dz' },
|
||||
{ name: 'ft', value: 'ft' },
|
||||
{ name: 'g', value: 'g' },
|
||||
{ name: 'in', value: 'in' },
|
||||
{ name: 'kg', value: 'kg' },
|
||||
{ name: 'km', value: 'km' },
|
||||
{ name: 'lb', value: 'lb' },
|
||||
{ name: 'mg', value: 'mg' },
|
||||
{ name: 'pc', value: 'pc' }
|
||||
],
|
||||
isRequestOngoing: true,
|
||||
filtersApplied: false,
|
||||
filters: {
|
||||
@ -262,7 +249,8 @@ export default {
|
||||
'items',
|
||||
'selectedItems',
|
||||
'totalItems',
|
||||
'selectAllField'
|
||||
'selectAllField',
|
||||
'itemUnits'
|
||||
]),
|
||||
...mapGetters('currency', [
|
||||
'defaultCurrency'
|
||||
@ -296,6 +284,7 @@ export default {
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
|
||||
destroyed () {
|
||||
if (this.selectAllField) {
|
||||
this.selectAllItems()
|
||||
@ -316,7 +305,7 @@ export default {
|
||||
async fetchData ({ page, filter, sort }) {
|
||||
let data = {
|
||||
search: this.filters.name !== null ? this.filters.name : '',
|
||||
unit: this.filters.unit !== null ? this.filters.unit.name : '',
|
||||
unit_id: this.filters.unit !== null ? this.filters.unit.id : '',
|
||||
price: this.filters.price * 100,
|
||||
orderByField: sort.fieldName || 'created_at',
|
||||
orderBy: sort.order || 'desc',
|
||||
@ -395,7 +384,7 @@ export default {
|
||||
}).then(async (willDelete) => {
|
||||
if (willDelete) {
|
||||
let res = await this.deleteMultipleItems()
|
||||
if (res.data.success) {
|
||||
if (res.data.success || res.data.items) {
|
||||
window.toastr['success'](this.$tc('items.deleted_message', 2))
|
||||
this.$refs.table.refresh()
|
||||
} else if (res.data.error) {
|
||||
|
||||
@ -109,12 +109,20 @@
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ $t('payments.payment_mode') }}</label>
|
||||
<base-select
|
||||
v-model="formData.payment_mode"
|
||||
:options="getPaymentMode"
|
||||
v-model="formData.payment_method"
|
||||
:options="paymentModes"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('payments.select_payment_mode')"
|
||||
/>
|
||||
label="name"
|
||||
>
|
||||
<div slot="afterList">
|
||||
<button type="button" class="list-add-button" @click="addPaymentMode">
|
||||
<font-awesome-icon class="icon" icon="cart-plus" />
|
||||
<label>{{ $t('settings.customization.payments.add_payment_mode') }}</label>
|
||||
</button>
|
||||
</div>
|
||||
</base-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 ">
|
||||
@ -166,9 +174,10 @@ export default {
|
||||
payment_number: null,
|
||||
payment_date: null,
|
||||
amount: 0,
|
||||
payment_mode: null,
|
||||
payment_method: null,
|
||||
invoice_id: null,
|
||||
notes: null
|
||||
notes: null,
|
||||
payment_method_id: null
|
||||
},
|
||||
money: {
|
||||
decimal: '.',
|
||||
@ -215,9 +224,9 @@ export default {
|
||||
...mapGetters('currency', [
|
||||
'defaultCurrencyForInput'
|
||||
]),
|
||||
getPaymentMode () {
|
||||
return ['Cash', 'Check', 'Credit Card', 'Bank Transfer']
|
||||
},
|
||||
...mapGetters('payment', [
|
||||
'paymentModes'
|
||||
]),
|
||||
amount: {
|
||||
get: function () {
|
||||
return this.formData.amount / 100
|
||||
@ -286,14 +295,23 @@ export default {
|
||||
'fetchCreatePayment',
|
||||
'addPayment',
|
||||
'updatePayment',
|
||||
'fetchPayment'
|
||||
'fetchEditPaymentData'
|
||||
]),
|
||||
...mapActions('modal', [
|
||||
'openModal'
|
||||
]),
|
||||
invoiceWithAmount ({ invoice_number, due_amount }) {
|
||||
return `${invoice_number} (${this.$utils.formatGraphMoney(due_amount, this.customer.currency)})`
|
||||
},
|
||||
async addPaymentMode () {
|
||||
this.openModal({
|
||||
'title': 'Add Payment Mode',
|
||||
'componentName': 'PaymentMode'
|
||||
})
|
||||
},
|
||||
async loadData () {
|
||||
if (this.isEdit) {
|
||||
let response = await this.fetchPayment(this.$route.params.id)
|
||||
let response = await this.fetchEditPaymentData(this.$route.params.id)
|
||||
this.customerList = response.data.customers
|
||||
this.formData = { ...response.data.payment }
|
||||
this.customer = response.data.payment.user
|
||||
@ -301,6 +319,7 @@ export default {
|
||||
this.formData.amount = parseFloat(response.data.payment.amount)
|
||||
this.paymentPrefix = response.data.payment_prefix
|
||||
this.paymentNumAttribute = response.data.nextPaymentNumber
|
||||
this.formData.payment_method = response.data.payment.payment_method
|
||||
if (response.data.payment.invoice !== null) {
|
||||
this.maxPayableAmount = parseInt(response.data.payment.amount) + parseInt(response.data.payment.invoice.due_amount)
|
||||
this.invoice = response.data.payment.invoice
|
||||
@ -344,6 +363,7 @@ export default {
|
||||
let data = {
|
||||
editData: {
|
||||
...this.formData,
|
||||
payment_method_id: this.formData.payment_method.id,
|
||||
payment_date: moment(this.formData.payment_date).format('DD/MM/YYYY')
|
||||
},
|
||||
id: this.$route.params.id
|
||||
@ -371,6 +391,7 @@ export default {
|
||||
} else {
|
||||
let data = {
|
||||
...this.formData,
|
||||
payment_method_id: this.formData.payment_method.id,
|
||||
payment_date: moment(this.formData.payment_date).format('DD/MM/YYYY')
|
||||
}
|
||||
this.isLoading = true
|
||||
|
||||
@ -67,10 +67,11 @@
|
||||
<label class="form-label">{{ $t('payments.payment_mode') }}</label>
|
||||
<base-select
|
||||
v-model="filters.payment_mode"
|
||||
:options="payment_mode"
|
||||
:options="paymentModes"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('payments.payment_mode')"
|
||||
label="name"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -203,6 +204,14 @@
|
||||
{{ $t('general.edit') }}
|
||||
</router-link>
|
||||
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item>
|
||||
|
||||
<router-link :to="{path: `payments/${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>
|
||||
<div class="dropdown-item" @click="removePayment(row.id)">
|
||||
@ -237,7 +246,6 @@ export default {
|
||||
sortedBy: 'created_at',
|
||||
filtersApplied: false,
|
||||
isRequestOngoing: true,
|
||||
payment_mode: ['Cash', 'Check', 'Credit Card', 'Bank Transfer'],
|
||||
filters: {
|
||||
customer: null,
|
||||
payment_mode: '',
|
||||
@ -259,7 +267,8 @@ export default {
|
||||
'selectedPayments',
|
||||
'totalPayments',
|
||||
'payments',
|
||||
'selectAllField'
|
||||
'selectAllField',
|
||||
'paymentModes'
|
||||
]),
|
||||
selectField: {
|
||||
get: function () {
|
||||
@ -308,7 +317,7 @@ export default {
|
||||
let data = {
|
||||
customer_id: this.filters.customer !== null ? this.filters.customer.id : '',
|
||||
payment_number: this.filters.payment_number,
|
||||
payment_mode: this.filters.payment_mode ? this.filters.payment_mode : '',
|
||||
payment_method_id: this.filters.payment_mode ? this.filters.payment_mode.id : '',
|
||||
orderByField: sort.fieldName || 'created_at',
|
||||
orderBy: sort.order || 'desc',
|
||||
page
|
||||
|
||||
286
resources/assets/js/views/payments/View.vue
Normal file
286
resources/assets/js/views/payments/View.vue
Normal file
@ -0,0 +1,286 @@
|
||||
<template>
|
||||
<div v-if="payment" class="main-content payment-view-page">
|
||||
<div class="page-header">
|
||||
<h3 class="page-title"> {{ payment.payment_number }}</h3>
|
||||
<div class="page-actions row">
|
||||
<base-button
|
||||
:loading="isSendingEmail"
|
||||
:disabled="isSendingEmail"
|
||||
:outline="true"
|
||||
color="theme"
|
||||
@click="onPaymentSend"
|
||||
>
|
||||
{{ $t('payments.send_payment_receipt') }}
|
||||
</base-button>
|
||||
<v-dropdown :close-on-select="false" 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"/>
|
||||
{{ $t('general.edit') }}
|
||||
</router-link>
|
||||
<div class="dropdown-item" @click="removePayment($route.params.id)">
|
||||
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
|
||||
{{ $t('general.delete') }}
|
||||
</div>
|
||||
</v-dropdown-item>
|
||||
</v-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="payment-sidebar">
|
||||
<div class="side-header">
|
||||
<base-input
|
||||
v-model="searchData.searchText"
|
||||
:placeholder="$t('general.search')"
|
||||
input-class="inv-search"
|
||||
icon="search"
|
||||
type="text"
|
||||
align-icon="right"
|
||||
@input="onSearch"
|
||||
/>
|
||||
<div
|
||||
class="btn-group ml-3"
|
||||
role="group"
|
||||
aria-label="First group"
|
||||
>
|
||||
<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">
|
||||
<font-awesome-icon icon="filter" />
|
||||
</base-button>
|
||||
</a>
|
||||
<div class="filter-title">
|
||||
{{ $t('general.sort_by') }}
|
||||
</div>
|
||||
<div class="filter-items">
|
||||
<input
|
||||
id="filter_invoice_number"
|
||||
v-model="searchData.orderByField"
|
||||
type="radio"
|
||||
name="filter"
|
||||
class="inv-radio"
|
||||
value="invoice_number"
|
||||
@change="onSearch"
|
||||
>
|
||||
<label class="inv-label" for="filter_invoice_number">{{ $t('invoices.title') }}</label>
|
||||
</div>
|
||||
<div class="filter-items">
|
||||
<input
|
||||
id="filter_payment_date"
|
||||
v-model="searchData.orderByField"
|
||||
type="radio"
|
||||
name="filter"
|
||||
class="inv-radio"
|
||||
value="payment_date"
|
||||
@change="onSearch"
|
||||
>
|
||||
<label class="inv-label" for="filter_payment_date">{{ $t('payments.date') }}</label>
|
||||
</div>
|
||||
<div class="filter-items">
|
||||
<input
|
||||
id="filter_payment_number"
|
||||
v-model="searchData.orderByField"
|
||||
type="radio"
|
||||
name="filter"
|
||||
class="inv-radio"
|
||||
value="payment_number"
|
||||
@change="onSearch"
|
||||
>
|
||||
<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">
|
||||
<font-awesome-icon v-if="getOrderBy" icon="sort-amount-up" />
|
||||
<font-awesome-icon v-else icon="sort-amount-down" />
|
||||
</base-button>
|
||||
</div>
|
||||
</div>
|
||||
<base-loader v-if="isSearching" />
|
||||
<div v-else class="side-content">
|
||||
<router-link
|
||||
v-for="(payment,index) in payments"
|
||||
:to="`/admin/payments/${payment.id}/view`"
|
||||
:key="index"
|
||||
class="side-payment"
|
||||
>
|
||||
<div class="left">
|
||||
<div class="inv-name">{{ payment.user.name }}</div>
|
||||
<div class="inv-number">{{ payment.payment_number }}</div>
|
||||
<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-date">{{ payment.formattedPaymentDate }}</div>
|
||||
<!-- <div class="inv-number">{{ payment.payment_method.name }}</div> -->
|
||||
</div>
|
||||
</router-link>
|
||||
<p v-if="!payments.length" class="no-result">
|
||||
{{ $t('payments.no_matching_invoices') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="payment-view-page-container" >
|
||||
<iframe :src="`${shareableLink}`" class="frame-style"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
const _ = require('lodash')
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
id: null,
|
||||
count: null,
|
||||
payments: [],
|
||||
payment: null,
|
||||
currency: null,
|
||||
searchData: {
|
||||
orderBy: null,
|
||||
orderByField: null,
|
||||
searchText: null
|
||||
},
|
||||
isRequestOnGoing: false,
|
||||
isSearching: false,
|
||||
isSendingEmail: false,
|
||||
isMarkingAsSent: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getOrderBy () {
|
||||
if (this.searchData.orderBy === 'asc' || this.searchData.orderBy == null) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
getOrderName () {
|
||||
if (this.getOrderBy) {
|
||||
return this.$t('general.ascending')
|
||||
}
|
||||
return this.$t('general.descending')
|
||||
},
|
||||
shareableLink () {
|
||||
return `/payments/pdf/${this.payment.unique_hash}`
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route (to, from) {
|
||||
this.loadPayment()
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.loadPayments()
|
||||
this.loadPayment()
|
||||
this.onSearch = _.debounce(this.onSearch, 500)
|
||||
},
|
||||
methods: {
|
||||
// ...mapActions('invoice', [
|
||||
// 'fetchInvoices',
|
||||
// 'getRecord',
|
||||
// 'searchInvoice',
|
||||
// 'markAsSent',
|
||||
// 'sendEmail',
|
||||
// 'deleteInvoice',
|
||||
// 'fetchViewInvoice'
|
||||
// ]),
|
||||
...mapActions('payment', [
|
||||
'fetchPayments',
|
||||
'fetchPayment',
|
||||
'sendEmail',
|
||||
'deletePayment',
|
||||
'searchPayment'
|
||||
]),
|
||||
async loadPayments () {
|
||||
let response = await this.fetchPayments()
|
||||
if (response.data) {
|
||||
this.payments = response.data.payments.data
|
||||
}
|
||||
},
|
||||
async loadPayment () {
|
||||
let response = await this.fetchPayment(this.$route.params.id)
|
||||
|
||||
if (response.data) {
|
||||
this.payment = response.data.payment
|
||||
}
|
||||
},
|
||||
async onSearch () {
|
||||
let data = ''
|
||||
if (this.searchData.searchText !== '' && this.searchData.searchText !== null && this.searchData.searchText !== undefined) {
|
||||
data += `search=${this.searchData.searchText}&`
|
||||
}
|
||||
|
||||
if (this.searchData.orderBy !== null && this.searchData.orderBy !== undefined) {
|
||||
data += `orderBy=${this.searchData.orderBy}&`
|
||||
}
|
||||
|
||||
if (this.searchData.orderByField !== null && this.searchData.orderByField !== undefined) {
|
||||
data += `orderByField=${this.searchData.orderByField}`
|
||||
}
|
||||
this.isSearching = true
|
||||
let response = await this.searchPayment(data)
|
||||
this.isSearching = false
|
||||
if (response.data) {
|
||||
this.payments = response.data.payments.data
|
||||
}
|
||||
},
|
||||
sortData () {
|
||||
if (this.searchData.orderBy === 'asc') {
|
||||
this.searchData.orderBy = 'desc'
|
||||
this.onSearch()
|
||||
return true
|
||||
}
|
||||
this.searchData.orderBy = 'asc'
|
||||
this.onSearch()
|
||||
return true
|
||||
},
|
||||
async onPaymentSend () {
|
||||
window.swal({
|
||||
title: this.$tc('general.are_you_sure'),
|
||||
text: this.$tc('payments.confirm_send_payment'),
|
||||
icon: '/assets/icon/paper-plane-solid.svg',
|
||||
buttons: true,
|
||||
dangerMode: true
|
||||
}).then(async (value) => {
|
||||
if (value) {
|
||||
this.isSendingEmail = true
|
||||
let response = await this.sendEmail({id: this.payment.id})
|
||||
this.isSendingEmail = false
|
||||
if (response.data.success) {
|
||||
window.toastr['success'](this.$tc('payments.send_payment_successfully'))
|
||||
return true
|
||||
}
|
||||
if (response.data.error === 'user_email_does_not_exist') {
|
||||
window.toastr['error'](this.$tc('payments.user_email_does_not_exist'))
|
||||
return false
|
||||
}
|
||||
window.toastr['error'](this.$tc('payments.something_went_wrong'))
|
||||
}
|
||||
})
|
||||
},
|
||||
async removePayment (id) {
|
||||
this.id = id
|
||||
window.swal({
|
||||
title: 'Deleted',
|
||||
text: 'you will not be able to recover this payment!',
|
||||
icon: '/assets/icon/trash-solid.svg',
|
||||
buttons: true,
|
||||
dangerMode: true
|
||||
}).then(async (value) => {
|
||||
if (value) {
|
||||
let request = await this.deletePayment(this.id)
|
||||
if (request.data.success) {
|
||||
window.toastr['success'](this.$tc('payments.deleted_message', 1))
|
||||
this.$router.push('/admin/payments')
|
||||
} else if (request.data.error) {
|
||||
window.toastr['error'](request.data.message)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -11,12 +11,15 @@
|
||||
<li class="tab" @click="setActiveTab('PAYMENTS')">
|
||||
<a :class="['tab-link', {'a-active': activeTab === 'PAYMENTS'}]" href="#">{{ $t('settings.customization.payments.title') }}</a>
|
||||
</li>
|
||||
<li class="tab" @click="setActiveTab('ITEMS')">
|
||||
<a :class="['tab-link', {'a-active': activeTab === 'ITEMS'}]" href="#">{{ $t('settings.customization.items.title') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Invoices Tab -->
|
||||
<transition name="fade-customize">
|
||||
<div v-if="activeTab === 'INVOICES'" class="invoice-tab">
|
||||
<form action="" class="form-section" @submit.prevent="updateInvoiceSetting">
|
||||
<form action="" class="mt-3" @submit.prevent="updateInvoiceSetting">
|
||||
<div class="row">
|
||||
<div class="col-md-12 mb-4">
|
||||
<label class="input-label">{{ $t('settings.customization.invoices.invoice_prefix') }}</label>
|
||||
@ -32,7 +35,7 @@
|
||||
<span v-if="!$v.invoices.invoice_prefix.alpha" class="text-danger">{{ $t('validation.characters_only') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="row pb-3">
|
||||
<div class="col-md-12">
|
||||
<base-button
|
||||
icon="save"
|
||||
@ -43,25 +46,23 @@
|
||||
</base-button>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
</form>
|
||||
<div class="col-md-12 mt-3">
|
||||
<div class="page-header">
|
||||
<h3 class="page-title">
|
||||
{{ $t('settings.customization.invoices.invoice_settings') }}
|
||||
</h3>
|
||||
<div class="flex-box">
|
||||
<div class="left">
|
||||
<base-switch
|
||||
v-model="invoiceAutogenerate"
|
||||
class="btn-switch"
|
||||
@change="setInvoiceSetting"
|
||||
/>
|
||||
</div>
|
||||
<div class="right ml-15">
|
||||
<p class="box-title"> {{ $t('settings.customization.invoices.autogenerate_invoice_number') }} </p>
|
||||
<p class="box-desc"> {{ $t('settings.customization.invoices.invoice_setting_description') }} </p>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="page-header pt-3">
|
||||
<h3 class="page-title">
|
||||
{{ $t('settings.customization.invoices.invoice_settings') }}
|
||||
</h3>
|
||||
<div class="flex-box">
|
||||
<div class="left">
|
||||
<base-switch
|
||||
v-model="invoiceAutogenerate"
|
||||
class="btn-switch"
|
||||
@change="setInvoiceSetting"
|
||||
/>
|
||||
</div>
|
||||
<div class="right ml-15">
|
||||
<p class="box-title"> {{ $t('settings.customization.invoices.autogenerate_invoice_number') }} </p>
|
||||
<p class="box-desc"> {{ $t('settings.customization.invoices.invoice_setting_description') }} </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -71,7 +72,7 @@
|
||||
<!-- Estimates Tab -->
|
||||
<transition name="fade-customize">
|
||||
<div v-if="activeTab === 'ESTIMATES'" class="estimate-tab">
|
||||
<form action="" class="form-section" @submit.prevent="updateEstimateSetting">
|
||||
<form action="" class="mt-3" @submit.prevent="updateEstimateSetting">
|
||||
<div class="row">
|
||||
<div class="col-md-12 mb-4">
|
||||
<label class="input-label">{{ $t('settings.customization.estimates.estimate_prefix') }}</label>
|
||||
@ -87,7 +88,7 @@
|
||||
<span v-if="!$v.estimates.estimate_prefix.alpha" class="text-danger">{{ $t('validation.characters_only') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="row pb-3">
|
||||
<div class="col-md-12">
|
||||
<base-button
|
||||
icon="save"
|
||||
@ -100,23 +101,21 @@
|
||||
</div>
|
||||
<hr>
|
||||
</form>
|
||||
<div class="col-md-12 mt-3">
|
||||
<div class="page-header">
|
||||
<h3 class="page-title">
|
||||
{{ $t('settings.customization.estimates.estimate_settings') }}
|
||||
</h3>
|
||||
<div class="flex-box">
|
||||
<div class="left">
|
||||
<base-switch
|
||||
v-model="estimateAutogenerate"
|
||||
class="btn-switch"
|
||||
@change="setEstimateSetting"
|
||||
/>
|
||||
</div>
|
||||
<div class="right ml-15">
|
||||
<p class="box-title"> {{ $t('settings.customization.estimates.autogenerate_estimate_number') }} </p>
|
||||
<p class="box-desc"> {{ $t('settings.customization.estimates.estimate_setting_description') }} </p>
|
||||
</div>
|
||||
<div class="page-header pt-3">
|
||||
<h3 class="page-title">
|
||||
{{ $t('settings.customization.estimates.estimate_settings') }}
|
||||
</h3>
|
||||
<div class="flex-box">
|
||||
<div class="left">
|
||||
<base-switch
|
||||
v-model="estimateAutogenerate"
|
||||
class="btn-switch"
|
||||
@change="setEstimateSetting"
|
||||
/>
|
||||
</div>
|
||||
<div class="right ml-15">
|
||||
<p class="box-title"> {{ $t('settings.customization.estimates.autogenerate_estimate_number') }} </p>
|
||||
<p class="box-desc"> {{ $t('settings.customization.estimates.estimate_setting_description') }} </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -126,7 +125,66 @@
|
||||
<!-- Payments Tab -->
|
||||
<transition name="fade-customize">
|
||||
<div v-if="activeTab === 'PAYMENTS'" class="payment-tab">
|
||||
<form action="" class="form-section" @submit.prevent="updatePaymentSetting">
|
||||
<div class="page-header">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<!-- <h3 class="page-title">
|
||||
{{ $t('settings.customization.payments.payment_mode') }}
|
||||
</h3> -->
|
||||
</div>
|
||||
<div class="col-md-4 d-flex flex-row-reverse">
|
||||
<base-button
|
||||
outline
|
||||
class="add-new-tax"
|
||||
color="theme"
|
||||
@click="addPaymentMode"
|
||||
>
|
||||
{{ $t('settings.customization.payments.add_payment_mode') }}
|
||||
</base-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table-component
|
||||
ref="table"
|
||||
:show-filter="false"
|
||||
:data="paymentModes"
|
||||
table-class="table tax-table"
|
||||
class="mb-3"
|
||||
>
|
||||
<table-column
|
||||
:sortable="true"
|
||||
:label="$t('settings.customization.payments.payment_mode')"
|
||||
show="name"
|
||||
/>
|
||||
<table-column
|
||||
:sortable="false"
|
||||
:filterable="false"
|
||||
cell-class="action-dropdown"
|
||||
>
|
||||
<template slot-scope="row">
|
||||
<span>{{ $t('settings.tax_types.action') }}</span>
|
||||
<v-dropdown>
|
||||
<a slot="activator" href="#">
|
||||
<dot-icon />
|
||||
</a>
|
||||
<v-dropdown-item>
|
||||
<div class="dropdown-item" @click="editPaymentMode(row)">
|
||||
<font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon" />
|
||||
{{ $t('general.edit') }}
|
||||
</div>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item>
|
||||
<div class="dropdown-item" @click="removePaymentMode(row.id)">
|
||||
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
|
||||
{{ $t('general.delete') }}
|
||||
</div>
|
||||
</v-dropdown-item>
|
||||
</v-dropdown>
|
||||
</template>
|
||||
</table-column>
|
||||
</table-component>
|
||||
<hr>
|
||||
<form action="" class="pt-3" @submit.prevent="updatePaymentSetting">
|
||||
<div class="row">
|
||||
<div class="col-md-12 mb-4">
|
||||
<label class="input-label">{{ $t('settings.customization.payments.payment_prefix') }}</label>
|
||||
@ -142,7 +200,7 @@
|
||||
<span v-if="!$v.payments.payment_prefix.alpha" class="text-danger">{{ $t('validation.characters_only') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="row pb-3">
|
||||
<div class="col-md-12">
|
||||
<base-button
|
||||
icon="save"
|
||||
@ -155,33 +213,97 @@
|
||||
</div>
|
||||
</form>
|
||||
<hr>
|
||||
<div class="col-md-12 mt-4">
|
||||
<div class="page-header">
|
||||
<h3 class="page-title">
|
||||
{{ $t('settings.customization.payments.payment_settings') }}
|
||||
</h3>
|
||||
<div class="flex-box">
|
||||
<div class="left">
|
||||
<base-switch
|
||||
v-model="paymentAutogenerate"
|
||||
class="btn-switch"
|
||||
@change="setPaymentSetting"
|
||||
/>
|
||||
</div>
|
||||
<div class="right ml-15">
|
||||
<p class="box-title"> {{ $t('settings.customization.payments.autogenerate_payment_number') }} </p>
|
||||
<p class="box-desc"> {{ $t('settings.customization.payments.payment_setting_description') }} </p>
|
||||
</div>
|
||||
<div class="page-header pt-3">
|
||||
<h3 class="page-title">
|
||||
{{ $t('settings.customization.payments.payment_settings') }}
|
||||
</h3>
|
||||
<div class="flex-box">
|
||||
<div class="left">
|
||||
<base-switch
|
||||
v-model="paymentAutogenerate"
|
||||
class="btn-switch"
|
||||
@change="setPaymentSetting"
|
||||
/>
|
||||
</div>
|
||||
<div class="right ml-15">
|
||||
<p class="box-title"> {{ $t('settings.customization.payments.autogenerate_payment_number') }} </p>
|
||||
<p class="box-desc"> {{ $t('settings.customization.payments.payment_setting_description') }} </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<!-- Items Tab -->
|
||||
<transition name="fade-customize">
|
||||
<div v-if="activeTab === 'ITEMS'" class="item-tab">
|
||||
<div class="page-header">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<!-- <h3 class="page-title">
|
||||
{{ $t('settings.customization.items.title') }}
|
||||
</h3> -->
|
||||
</div>
|
||||
<div class="col-md-4 d-flex flex-row-reverse">
|
||||
<base-button
|
||||
outline
|
||||
class="add-new-tax"
|
||||
color="theme"
|
||||
@click="addItemUnit"
|
||||
>
|
||||
{{ $t('settings.customization.items.add_item_unit') }}
|
||||
</base-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table-component
|
||||
ref="itemTable"
|
||||
:show-filter="false"
|
||||
:data="itemUnits"
|
||||
table-class="table tax-table"
|
||||
class="mb-3"
|
||||
>
|
||||
<table-column
|
||||
:sortable="true"
|
||||
:label="$t('settings.customization.items.units')"
|
||||
show="name"
|
||||
/>
|
||||
<table-column
|
||||
:sortable="false"
|
||||
:filterable="false"
|
||||
cell-class="action-dropdown"
|
||||
>
|
||||
<template slot-scope="row">
|
||||
<span>{{ $t('settings.tax_types.action') }}</span>
|
||||
<v-dropdown>
|
||||
<a slot="activator" href="#">
|
||||
<dot-icon />
|
||||
</a>
|
||||
<v-dropdown-item>
|
||||
<div class="dropdown-item" @click="editItemUnit(row)">
|
||||
<font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon" />
|
||||
{{ $t('general.edit') }}
|
||||
</div>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item>
|
||||
<div class="dropdown-item" @click="removeItemUnit(row.id)">
|
||||
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
|
||||
{{ $t('general.delete') }}
|
||||
</div>
|
||||
</v-dropdown-item>
|
||||
</v-dropdown>
|
||||
</template>
|
||||
</table-column>
|
||||
</table-component>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { validationMixin } from 'vuelidate'
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
const { required, maxLength, alpha } = require('vuelidate/lib/validators')
|
||||
export default {
|
||||
mixins: [validationMixin],
|
||||
@ -204,9 +326,20 @@ export default {
|
||||
payments: {
|
||||
payment_prefix: null
|
||||
},
|
||||
items: {
|
||||
units: []
|
||||
},
|
||||
currentData: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('item', [
|
||||
'itemUnits'
|
||||
]),
|
||||
...mapGetters('payment', [
|
||||
'paymentModes'
|
||||
])
|
||||
},
|
||||
watch: {
|
||||
activeTab () {
|
||||
this.loadData()
|
||||
@ -239,6 +372,15 @@ export default {
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
...mapActions('modal', [
|
||||
'openModal'
|
||||
]),
|
||||
...mapActions('payment', [
|
||||
'deletePaymentMode'
|
||||
]),
|
||||
...mapActions('item', [
|
||||
'deleteItemUnit'
|
||||
]),
|
||||
async setInvoiceSetting () {
|
||||
let data = {
|
||||
key: 'invoice_auto_generate',
|
||||
@ -259,6 +401,78 @@ export default {
|
||||
window.toastr['success'](this.$t('general.setting_updated'))
|
||||
}
|
||||
},
|
||||
async addItemUnit () {
|
||||
this.openModal({
|
||||
'title': 'Add Item Unit',
|
||||
'componentName': 'ItemUnit'
|
||||
})
|
||||
this.$refs.itemTable.refresh()
|
||||
},
|
||||
async editItemUnit (data) {
|
||||
this.openModal({
|
||||
'title': 'Edit Item Unit',
|
||||
'componentName': 'ItemUnit',
|
||||
'id': data.id,
|
||||
'data': data
|
||||
})
|
||||
this.$refs.itemTable.refresh()
|
||||
},
|
||||
async removeItemUnit (id) {
|
||||
swal({
|
||||
title: this.$t('general.are_you_sure'),
|
||||
text: this.$t('settings.customization.items.item_unit_confirm_delete'),
|
||||
icon: '/assets/icon/trash-solid.svg',
|
||||
buttons: true,
|
||||
dangerMode: true
|
||||
}).then(async (value) => {
|
||||
if (value) {
|
||||
let response = await this.deleteItemUnit(id)
|
||||
if (response.data.success) {
|
||||
window.toastr['success'](this.$t('settings.customization.items.deleted_message'))
|
||||
this.id = null
|
||||
this.$refs.itemTable.refresh()
|
||||
return true
|
||||
}
|
||||
window.toastr['error'](this.$t('settings.customization.items.already_in_use'))
|
||||
}
|
||||
})
|
||||
},
|
||||
async addPaymentMode () {
|
||||
this.openModal({
|
||||
'title': 'Add Payment Mode',
|
||||
'componentName': 'PaymentMode'
|
||||
})
|
||||
this.$refs.table.refresh()
|
||||
},
|
||||
async editPaymentMode (data) {
|
||||
this.openModal({
|
||||
'title': 'Edit Payment Mode',
|
||||
'componentName': 'PaymentMode',
|
||||
'id': data.id,
|
||||
'data': data
|
||||
})
|
||||
this.$refs.table.refresh()
|
||||
},
|
||||
removePaymentMode (id) {
|
||||
swal({
|
||||
title: this.$t('general.are_you_sure'),
|
||||
text: this.$t('settings.customization.payments.payment_mode_confirm_delete'),
|
||||
icon: '/assets/icon/trash-solid.svg',
|
||||
buttons: true,
|
||||
dangerMode: true
|
||||
}).then(async (value) => {
|
||||
if (value) {
|
||||
let response = await this.deletePaymentMode(id)
|
||||
if (response.data.success) {
|
||||
window.toastr['success'](this.$t('settings.customization.payments.deleted_message'))
|
||||
this.id = null
|
||||
this.$refs.table.refresh()
|
||||
return true
|
||||
}
|
||||
window.toastr['error'](this.$t('settings.customization.payments.already_in_use'))
|
||||
}
|
||||
})
|
||||
},
|
||||
changeToUppercase (currentTab) {
|
||||
if (currentTab === 'INVOICES') {
|
||||
this.invoices.invoice_prefix = this.invoices.invoice_prefix.toUpperCase()
|
||||
|
||||
@ -15,7 +15,19 @@
|
||||
:mail-drivers="mail_drivers"
|
||||
@on-change-driver="(val) => mail_driver = mailConfigData.mail_driver = val"
|
||||
@submit-data="saveEmailConfig"
|
||||
/>
|
||||
>
|
||||
<base-button
|
||||
:loading="loading"
|
||||
outline
|
||||
class="pull-right mt-4 ml-2"
|
||||
icon="check"
|
||||
color="theme"
|
||||
type="button"
|
||||
@click="openMailTestModal"
|
||||
>
|
||||
{{ $t('general.test_mail_conf') }}
|
||||
</base-button>
|
||||
</component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -27,6 +39,7 @@ import Smtp from './mailDriver/Smtp'
|
||||
import Mailgun from './mailDriver/Mailgun'
|
||||
import Ses from './mailDriver/Ses'
|
||||
import Basic from './mailDriver/Basic'
|
||||
import { mapActions } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -50,6 +63,9 @@ export default {
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
...mapActions('modal', [
|
||||
'openModal'
|
||||
]),
|
||||
async loadData () {
|
||||
this.loading = true
|
||||
|
||||
@ -79,6 +95,12 @@ export default {
|
||||
} catch (e) {
|
||||
window.toastr['error']('Something went wrong')
|
||||
}
|
||||
},
|
||||
openMailTestModal () {
|
||||
this.openModal({
|
||||
'title': 'Test Mail Configuration',
|
||||
'componentName': 'MailTestModal'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,15 +73,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('general.save') }}
|
||||
</base-button>
|
||||
<div class="d-flex">
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('general.save') }}
|
||||
</base-button>
|
||||
<slot/>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
@ -167,15 +167,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('general.save') }}
|
||||
</base-button>
|
||||
<div class="d-flex">
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('general.save') }}
|
||||
</base-button>
|
||||
<slot/>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
@ -146,15 +146,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('general.save') }}
|
||||
</base-button>
|
||||
<div class="d-flex">
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('general.save') }}
|
||||
</base-button>
|
||||
<slot/>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
@ -146,15 +146,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('general.save') }}
|
||||
</base-button>
|
||||
<div class="d-flex">
|
||||
<base-button
|
||||
:loading="loading"
|
||||
class="pull-right mt-4"
|
||||
icon="save"
|
||||
color="theme"
|
||||
type="submit"
|
||||
>
|
||||
{{ $t('general.save') }}
|
||||
</base-button>
|
||||
<slot/>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
@ -54,7 +54,6 @@
|
||||
:placeholder="$t('general.select_country')"
|
||||
track-by="id"
|
||||
label="name"
|
||||
@input="fetchState()"
|
||||
/>
|
||||
<div v-if="$v.companyData.country_id.$error">
|
||||
<span v-if="!$v.companyData.country_id.required" class="text-danger">{{ $tc('validation.required') }}</span>
|
||||
|
||||
44
resources/assets/sass/components/item-unit-modal.scss
vendored
Normal file
44
resources/assets/sass/components/item-unit-modal.scss
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
.item-unit-modal {
|
||||
|
||||
.card-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 20px 20px;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
text-align: end;
|
||||
padding-right: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.required {
|
||||
position: absolute;
|
||||
// left: -10px;
|
||||
color: $ls-color-red;
|
||||
}
|
||||
|
||||
.compound-tax-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 9px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media(max-width: $x-small-breakpoint ) {
|
||||
|
||||
.base-modal {
|
||||
|
||||
.item-unit-modal {
|
||||
width: 100vw;
|
||||
|
||||
.input-label {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
44
resources/assets/sass/components/mail-test-modal.scss
vendored
Normal file
44
resources/assets/sass/components/mail-test-modal.scss
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
.mail-test-modal {
|
||||
|
||||
.card-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 20px 20px;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
text-align: end;
|
||||
padding-right: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.required {
|
||||
position: absolute;
|
||||
margin-left: 4px;
|
||||
color: $ls-color-red;
|
||||
}
|
||||
|
||||
.compound-tax-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 9px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media(max-width: $x-small-breakpoint ) {
|
||||
|
||||
.base-modal {
|
||||
|
||||
.mail-test-modal {
|
||||
width: 100vw;
|
||||
|
||||
.input-label {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
44
resources/assets/sass/components/payment-modes-modal.scss
vendored
Normal file
44
resources/assets/sass/components/payment-modes-modal.scss
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
.payment-modes-modal {
|
||||
|
||||
.card-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 20px 20px;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
text-align: end;
|
||||
padding-right: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.required {
|
||||
position: absolute;
|
||||
// left: -10px;
|
||||
color: $ls-color-red;
|
||||
}
|
||||
|
||||
.compound-tax-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 9px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media(max-width: $x-small-breakpoint ) {
|
||||
|
||||
.base-modal {
|
||||
|
||||
.payment-modes-modal-modal {
|
||||
width: 100vw;
|
||||
|
||||
.input-label {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
109
resources/assets/sass/components/v-tooltips.scss
vendored
Normal file
109
resources/assets/sass/components/v-tooltips.scss
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
.tooltip {
|
||||
display: block !important;
|
||||
z-index: 10000;
|
||||
|
||||
.tooltip-inner {
|
||||
background: black;
|
||||
color: white;
|
||||
border-radius: 16px;
|
||||
padding: 5px 10px 4px;
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
position: absolute;
|
||||
margin: 5px;
|
||||
border-color: black;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&[x-placement^="top"] {
|
||||
margin-bottom: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 5px 5px 0 5px;
|
||||
border-left-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
bottom: -5px;
|
||||
left: calc(50% - 5px);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="bottom"] {
|
||||
margin-top: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 0 5px 5px 5px;
|
||||
border-left-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-top-color: transparent !important;
|
||||
top: -5px;
|
||||
left: calc(50% - 5px);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="right"] {
|
||||
margin-left: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 5px 5px 5px 0;
|
||||
border-left-color: transparent !important;
|
||||
border-top-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
left: -5px;
|
||||
top: calc(50% - 5px);
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&[x-placement^="left"] {
|
||||
margin-right: 5px;
|
||||
|
||||
.tooltip-arrow {
|
||||
border-width: 5px 0 5px 5px;
|
||||
border-top-color: transparent !important;
|
||||
border-right-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
right: -5px;
|
||||
top: calc(50% - 5px);
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.popover {
|
||||
$color: #f9f9f9;
|
||||
|
||||
.popover-inner {
|
||||
background: $color;
|
||||
color: black;
|
||||
padding: 24px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 5px 30px rgba(black, .1);
|
||||
}
|
||||
|
||||
.popover-arrow {
|
||||
border-color: $color;
|
||||
}
|
||||
}
|
||||
|
||||
&[aria-hidden='true'] {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity .15s, visibility .15s;
|
||||
}
|
||||
|
||||
&[aria-hidden='false'] {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity .15s;
|
||||
}
|
||||
}
|
||||
5
resources/assets/sass/crater.scss
vendored
5
resources/assets/sass/crater.scss
vendored
@ -49,6 +49,7 @@
|
||||
@import "components/base/base-switch";
|
||||
@import 'components/base/base-loader/index';
|
||||
@import 'components/base/base-prefix-input';
|
||||
@import 'components/v-tooltips.scss';
|
||||
|
||||
|
||||
// Components
|
||||
@ -72,6 +73,9 @@
|
||||
@import "components/item-select";
|
||||
@import "components/tax-select";
|
||||
@import "components/avatar-cropper";
|
||||
@import "components/payment-modes-modal";
|
||||
@import "components/item-unit-modal.scss";
|
||||
@import "components/mail-test-modal.scss";
|
||||
|
||||
|
||||
// Modals
|
||||
@ -107,5 +111,6 @@
|
||||
@import 'pages/reports.scss';
|
||||
@import 'pages/customers';
|
||||
@import 'pages/payments.scss';
|
||||
@import 'pages/payment-view.scss';
|
||||
@import 'pages/items.scss';
|
||||
@import 'pages/statuses.scss';
|
||||
|
||||
15
resources/assets/sass/pages/estimates/view.scss
vendored
15
resources/assets/sass/pages/estimates/view.scss
vendored
@ -158,6 +158,7 @@
|
||||
border: 1px solid #eaf1fb;
|
||||
box-sizing: border-box;
|
||||
color: $ls-color-gray--dark;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,8 +191,17 @@
|
||||
|
||||
.filter-container {
|
||||
margin-left: 12px;
|
||||
|
||||
.filter-title {
|
||||
padding: 5px 10px;
|
||||
border-bottom: 1px solid rgba(185, 193, 209, 0.41);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.filter-items {
|
||||
display: flex;
|
||||
padding: 4px 9px;
|
||||
cursor: pointer;
|
||||
|
||||
&:first-child {
|
||||
margin-top: auto;
|
||||
@ -202,11 +212,12 @@
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
line-height: 12px;
|
||||
text-transform: capitalize;
|
||||
color: $ls-color-black;
|
||||
margin-bottom: 6px;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.base-input {
|
||||
@ -214,7 +225,7 @@
|
||||
}
|
||||
|
||||
.dropdown-container {
|
||||
padding: 11px;
|
||||
padding: 0px !important;
|
||||
left: auto;
|
||||
right: 0px;
|
||||
width: 166px;
|
||||
|
||||
@ -87,7 +87,7 @@
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: $ls-color-primary;
|
||||
margin: 0 0 0 0;
|
||||
margin: 0 9px 0 0;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
15
resources/assets/sass/pages/invoices/view.scss
vendored
15
resources/assets/sass/pages/invoices/view.scss
vendored
@ -113,6 +113,7 @@
|
||||
border: 1px solid $ls-color-gray--light;
|
||||
box-sizing: border-box;
|
||||
color: $ls-color-gray;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
}
|
||||
@ -148,9 +149,18 @@
|
||||
|
||||
.filter-container {
|
||||
margin-left: 12px;
|
||||
|
||||
.filter-title {
|
||||
padding: 5px 10px;
|
||||
border-bottom: 1px solid rgba(185, 193, 209, 0.41);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.filter-items {
|
||||
// margin-top: 10px;
|
||||
display: flex;
|
||||
padding: 4px 9px;
|
||||
cursor: pointer;
|
||||
|
||||
&:first-child {
|
||||
margin-top: auto;
|
||||
@ -162,11 +172,12 @@
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
line-height: 12px;
|
||||
text-transform: capitalize;
|
||||
color: $ls-color-black;
|
||||
margin-bottom: 6px;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.base-input {
|
||||
@ -174,7 +185,7 @@
|
||||
}
|
||||
|
||||
.dropdown-container {
|
||||
padding: 11px;
|
||||
padding: 0px !important;
|
||||
left: auto;
|
||||
right: 0px;
|
||||
width: 155px;
|
||||
|
||||
238
resources/assets/sass/pages/payment-view.scss
vendored
Normal file
238
resources/assets/sass/pages/payment-view.scss
vendored
Normal file
@ -0,0 +1,238 @@
|
||||
// Payments - View
|
||||
// -------------------------
|
||||
|
||||
.payment-view-page {
|
||||
padding-left: 570px !important;
|
||||
|
||||
.payment-sidebar {
|
||||
width: 300px;
|
||||
height: 100vh;
|
||||
height: 100%;
|
||||
left: 240px;
|
||||
padding: 60px 0 10px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 300px;
|
||||
z-index: 25;
|
||||
background: #FFFFFF;
|
||||
}
|
||||
|
||||
.inv-search {
|
||||
background: $ls-color-gray--very-light !important;
|
||||
}
|
||||
|
||||
.side-payment {
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid rgba(185, 193, 209, 0.41);
|
||||
cursor: pointer;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 98px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $ls-color-gray--very-light;
|
||||
}
|
||||
|
||||
.left {
|
||||
|
||||
.inv-name {
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
text-transform: capitalize;
|
||||
color: $ls-color-black;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.inv-number {
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
color: $ls-color-gray--dark;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.inv-status {
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 10px;
|
||||
line-height: 15px;
|
||||
padding: 2px 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.right {
|
||||
|
||||
.inv-amount {
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
line-height: 30px;
|
||||
text-align: right;
|
||||
color: $ls-color-black--light;
|
||||
}
|
||||
|
||||
.inv-date {
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
text-align: right;
|
||||
color: $ls-color-gray--dark;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.no-result {
|
||||
color: $ls-color-gray;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.side-header {
|
||||
|
||||
height: 100px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30px 15px;
|
||||
border-bottom: 1px solid rgba(185, 193, 209, 0.41);
|
||||
|
||||
.inv-button {
|
||||
background: $ls-color-gray--very-light;
|
||||
border: 1px solid $ls-color-gray--light;
|
||||
box-sizing: border-box;
|
||||
color: $ls-color-gray;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.side-content {
|
||||
overflow-y: scroll;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.payment-view-page-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 75vh;
|
||||
min-height: 0;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.frame-style {
|
||||
flex: 1 1 auto;
|
||||
border: 1px solid $ls-color-gray;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.inv-filter-fields-btn, .inv-filter-sorting-btn {
|
||||
|
||||
&:focus {
|
||||
border-color: inherit;
|
||||
box-shadow: none;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
margin-left: 12px;
|
||||
|
||||
.filter-title {
|
||||
padding: 5px 10px;
|
||||
border-bottom: 1px solid rgba(185, 193, 209, 0.41);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.filter-items {
|
||||
// margin-top: 10px;
|
||||
display: flex;
|
||||
padding: 4px 9px;
|
||||
cursor: pointer;
|
||||
|
||||
&:first-child {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.inv-label {
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 12px;
|
||||
text-transform: capitalize;
|
||||
color: $ls-color-black;
|
||||
margin-bottom: 6px;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.base-input {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.dropdown-container {
|
||||
padding: 0px !important;
|
||||
left: auto;
|
||||
right: 0px;
|
||||
width: 167px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.filter-payment-date {
|
||||
|
||||
.vdp-datepicker {
|
||||
|
||||
div {
|
||||
|
||||
.vdp-datepicker__clear-button {
|
||||
margin-left: -21px;
|
||||
margin-top: 2px;
|
||||
font-size: 20px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.date-group {
|
||||
display: flex
|
||||
}
|
||||
|
||||
.to-text {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: $small-breakpoint) {
|
||||
|
||||
.payment-view-page {
|
||||
padding-left: 310px !important;
|
||||
}
|
||||
|
||||
.payment-sidebar {
|
||||
transition: .2s all;
|
||||
left: 0px !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
19
resources/assets/sass/pages/settings.scss
vendored
19
resources/assets/sass/pages/settings.scss
vendored
@ -104,9 +104,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
.payment-tab {
|
||||
|
||||
.dropdown-container {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.item-tab {
|
||||
|
||||
.dropdown-container {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.add-new-tax {
|
||||
height: 45px;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.flex-box {
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Estimate</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">
|
||||
@ -19,13 +18,18 @@
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
hr {
|
||||
.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);
|
||||
border: 0.5px solid #EAF1FB;
|
||||
}
|
||||
|
||||
.header-center {
|
||||
@ -250,8 +254,7 @@
|
||||
|
||||
.table2 {
|
||||
margin-top: 35px;
|
||||
border-bottom: 1px solid #EAF1FB;
|
||||
padding: 0px 30px 0 30px;
|
||||
padding: 0px 30px 10px 30px;
|
||||
page-break-before: avoid;
|
||||
page-break-after: auto;
|
||||
}
|
||||
@ -265,6 +268,7 @@
|
||||
text-align: center;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
padding: 5px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
tr.main-table-header th {
|
||||
@ -275,6 +279,10 @@
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.main-table-header {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
tr.item-details td {
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
@ -287,6 +295,7 @@
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.padd8 {
|
||||
@ -379,7 +388,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr class="header-line" style="border: 0.620315px solid #E8E8E8;" />
|
||||
<hr class="header-line" />
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<div class="address">
|
||||
|
||||
@ -2,9 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Estimate</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">
|
||||
body {
|
||||
font-family: "DejaVu Sans";
|
||||
@ -25,7 +23,6 @@
|
||||
display:inline-block;
|
||||
width:30%;
|
||||
}
|
||||
|
||||
@page {
|
||||
margin-top: 60px !important;
|
||||
}
|
||||
@ -80,7 +77,8 @@
|
||||
}
|
||||
|
||||
.address {
|
||||
display: inline-block;
|
||||
display: block;
|
||||
padding-top: 20px;
|
||||
}
|
||||
.company {
|
||||
padding: 0 0 0 30px;
|
||||
@ -110,8 +108,8 @@
|
||||
/* -------------------------- */
|
||||
/* billing style */
|
||||
.bill-address-container {
|
||||
display: inline;
|
||||
position: absolute;
|
||||
display: block;
|
||||
/* position: absolute; */
|
||||
float:right;
|
||||
padding: 0 40px 0 0;
|
||||
}
|
||||
@ -159,8 +157,7 @@
|
||||
/* -------------------------- */
|
||||
/* shipping style */
|
||||
.ship-address-container {
|
||||
display: inline;
|
||||
position: absolute;
|
||||
display: block;
|
||||
float:right;
|
||||
padding: 0 30px 0 0;
|
||||
}
|
||||
@ -247,13 +244,18 @@
|
||||
}
|
||||
|
||||
.table2 {
|
||||
margin-top: 200px;
|
||||
border-bottom: 1px solid #EAF1FB;
|
||||
padding: 0px 30px 0 30px;
|
||||
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;
|
||||
}
|
||||
@ -285,6 +287,7 @@
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.note-header {
|
||||
@ -317,6 +320,16 @@
|
||||
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;
|
||||
@ -402,6 +415,7 @@
|
||||
<h1 class="header-logo"> {{$estimate->user->company->name}} </h1>
|
||||
@endif
|
||||
@endif
|
||||
</td>
|
||||
<td width="40%" class="header-right company-details">
|
||||
<h1>Estimate</h1>
|
||||
<h4>{{$estimate->estimate_number}}</h4>
|
||||
@ -426,6 +440,7 @@
|
||||
@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')
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Estimate</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">
|
||||
@ -18,7 +17,7 @@
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
hr {
|
||||
.header-line {
|
||||
color:rgba(0, 0, 0, 0.2);
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
@ -27,6 +26,15 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
hr {
|
||||
color:rgba(0, 0, 0, 0.2);
|
||||
border: 0.5px solid #EAF1FB;
|
||||
}
|
||||
|
||||
.items-table-hr{
|
||||
margin: 0 30px 0 30px;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
padding-top: 45px;
|
||||
padding-bottom: 45px;
|
||||
@ -34,6 +42,7 @@
|
||||
display:inline-block;
|
||||
width:30%;
|
||||
}
|
||||
|
||||
.header-table {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
@ -87,7 +96,7 @@
|
||||
|
||||
.address {
|
||||
display: inline-block;
|
||||
padding-top: 20px
|
||||
padding-top: 100px
|
||||
}
|
||||
|
||||
.bill-add {
|
||||
@ -201,8 +210,7 @@
|
||||
|
||||
|
||||
.job-add {
|
||||
display: inline;
|
||||
position: absolute;
|
||||
display: block;
|
||||
float: right;
|
||||
padding: 20px 30px 0 0;
|
||||
}
|
||||
@ -251,9 +259,7 @@
|
||||
line-height: 18px;
|
||||
}
|
||||
.table2 {
|
||||
margin-top: 188px;
|
||||
border-bottom: 1px solid #EAF1FB;
|
||||
padding: 0px 30px 0 30px;
|
||||
padding: 0px 30px 10px 30px;
|
||||
page-break-before: avoid;
|
||||
page-break-after: auto;
|
||||
}
|
||||
@ -417,7 +423,9 @@
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<hr style="border: 0.620315px solid #E8E8E8;">
|
||||
|
||||
<hr class="header-line">
|
||||
|
||||
<div class="wrapper">
|
||||
<div class="address">
|
||||
<div class="bill-add">
|
||||
@ -450,6 +458,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
</div>
|
||||
@include('app.pdf.estimate.partials.table')
|
||||
@include('app.pdf.estimate.partials.notes')
|
||||
|
||||
@ -3,6 +3,6 @@
|
||||
<div class="notes-label">
|
||||
Notes
|
||||
</div>
|
||||
{{$estimate->notes}}
|
||||
{!! nl2br(htmlspecialchars($estimate->notes)) !!}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@ -1,17 +1,13 @@
|
||||
<table width="100%" class="table2" cellspacing="0" border="0">
|
||||
<tr class="main-table-header">
|
||||
<th class="ItemTableHeader" style="text-align: right; color: #55547A; padding-right: 20px">#</th>
|
||||
@if($estimate->discount_per_item === 'NO')
|
||||
<th width="80%" class="ItemTableHeader" style="text-align: left; color: #55547A; padding-left: 0px">Items</th>
|
||||
@else
|
||||
<th width="40%" class="ItemTableHeader" style="text-align: left; color: #55547A; padding-left: 0px">Items</th>
|
||||
@endif
|
||||
<th width="17%" class="ItemTableHeader" style="text-align: right; color: #55547A; padding-right: 20px">Quantity</th>
|
||||
<th width="18%" class="ItemTableHeader" style="text-align: right; color: #55547A; padding-right: 40px">Price</th>
|
||||
<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>
|
||||
@if($estimate->discount_per_item === 'YES')
|
||||
<th width="10%" class="ItemTableHeader" style="text-align: right; color: #55547A; padding-left: 10px">Discount</th>
|
||||
<th class="ItemTableHeader" style="text-align: right; color: #55547A; padding-left: 10px">Discount</th>
|
||||
@endif
|
||||
<th width="15%" class="ItemTableHeader" style="text-align: right; color: #55547A;">Amount</th>
|
||||
<th class="ItemTableHeader" style="text-align: right; color: #55547A;">Amount</th>
|
||||
</tr>
|
||||
@php
|
||||
$index = 1
|
||||
@ -32,7 +28,7 @@
|
||||
<span
|
||||
style="text-align: left; color: #595959; font-size: 9px; font-weight:300; line-height: 12px;"
|
||||
>
|
||||
{{ $item->description }}
|
||||
{!! nl2br(htmlspecialchars($item->description)) !!}
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
@ -43,7 +39,7 @@
|
||||
</td>
|
||||
<td
|
||||
class="inv-item items"
|
||||
style="text-align: right; color: #040405; padding-right: 40px"
|
||||
style="text-align: right; color: #040405; padding-right: 20px"
|
||||
>
|
||||
{!! format_money_pdf($item->price, $estimate->user->currency) !!}
|
||||
</td>
|
||||
@ -67,7 +63,9 @@
|
||||
@endforeach
|
||||
</table>
|
||||
|
||||
<table width="100%" cellspacing="0px" style="margin-left:420px" border="0" class="table3 @if(count($estimate->items) > 12) page-break @endif">
|
||||
<hr class="items-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">
|
||||
<tr>
|
||||
<td class="no-borde" style="color: #55547A; padding-left:10px; font-size:12px;">Subtotal</td>
|
||||
<td class="no-border items"
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
<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">
|
||||
@ -20,13 +19,18 @@
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
hr {
|
||||
.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);
|
||||
border: 0.5px solid #EAF1FB;
|
||||
}
|
||||
|
||||
.header-center {
|
||||
@ -251,8 +255,7 @@
|
||||
|
||||
.table2 {
|
||||
margin-top: 35px;
|
||||
border-bottom: 1px solid #EAF1FB;
|
||||
padding: 0px 30px 0 30px;
|
||||
padding: 0px 30px 10px 30px;
|
||||
page-break-before: avoid;
|
||||
page-break-after: auto;
|
||||
}
|
||||
@ -289,6 +292,7 @@
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.padd8 {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user