Merge branch 'master' of https://gitlab.com/mohit.panjvani/crater-web into fix-view-status

This commit is contained in:
satyaprakash10
2019-11-15 13:05:20 +05:30
49 changed files with 505 additions and 138 deletions

View File

@ -0,0 +1,31 @@
<?php
namespace Laraspace\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class UpdateFinished
{
use Dispatchable;
public $new;
public $old;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($old, $new)
{
$this->old = $old;
$this->new = $new;
}
}

View File

@ -54,7 +54,7 @@ class AccessTokensController extends Controller
{
$request->validate([
'username' => 'required|email',
'password' => 'required|string',
'password' => 'required|string|min:8',
]);
if ($this->hasTooManyLoginAttempts($request)) {

View File

@ -37,6 +37,7 @@ class EnvironmentController extends Controller
if(array_key_exists("success", $results)) {
Artisan::call('config:clear');
Artisan::call('key:generate --force');
Artisan::call('migrate --seed');
Artisan::call('migrate', ['--path' => 'vendor/laravel/passport/database/migrations']);

View File

@ -260,6 +260,7 @@ class InvoicesController extends Controller
'error' => 'invalid_due_amount'
]);
} elseif ($invoice->due_amount != 0 && $invoice->paid_status == Invoice::STATUS_PAID) {
$invoice->status = $invoice->getPreviousStatus();
$invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID;
}

View File

@ -170,6 +170,7 @@ class PaymentController extends Controller
$invoice->status = Invoice::STATUS_COMPLETED;
$invoice->paid_status = Invoice::STATUS_PAID;
} else {
$invoice->status = $invoice->getPreviousStatus();
$invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID;
}
@ -211,16 +212,7 @@ class PaymentController extends Controller
$invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID;
}
if ($invoice->due_date < Carbon::now()) {
$invoice->status = Invoice::STATUS_OVERDUE;
} elseif ($invoice->viewed) {
$invoice->status = Invoice::STATUS_VIEWED;
} elseif ($invoice->sent) {
$invoice->status = Invoice::STATUS_SENT;
} else {
$invoice->status = Invoice::STATUS_DRAFT;
}
$invoice->status = $invoice->getPreviousStatus();
$invoice->save();
}
@ -246,16 +238,7 @@ class PaymentController extends Controller
$invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID;
}
if ($invoice->due_date < Carbon::now()) {
$invoice->status = Invoice::STATUS_OVERDUE;
} elseif ($invoice->sent) {
$invoice->status = Invoice::STATUS_SENT;
} elseif ($invoice->viewed) {
$invoice->status = Invoice::STATUS_VIEWED;
} else {
$invoice->status = Invoice::STATUS_DRAFT;
}
$invoice->status = $invoice->getPreviousStatus();
$invoice->save();
}

View File

@ -26,8 +26,7 @@ class ReportController extends Controller
$query->whereBetween(
'invoice_date',
[$start->format('Y-m-d'), $end->format('Y-m-d')]
)
->where('paid_status', Invoice::STATUS_PAID);
);
}])
->customer()
->whereCompany($company->id)

View File

@ -0,0 +1,28 @@
<?php
namespace Laraspace\Http\Controllers;
use Illuminate\Http\Request;
use Laraspace\Space\Updater;
use Laraspace\Space\SiteApi;
class UpdateController extends Controller
{
public function update(Request $request)
{
set_time_limit(600); // 10 minutes
$json = Updater::update($request->installed, $request->version);
return response()->json($json);
}
public function checkLatestVersion(Request $request)
{
set_time_limit(600); // 10 minutes
$json = Updater::checkForUpdate();
return response()->json($json);
}
}

View File

@ -26,12 +26,16 @@ class CustomerRequest extends FormRequest
case 'POST':
return [
'name' => 'required',
'addresses.*.address_street_1' => 'max:255',
'addresses.*.address_street_2' => 'max:255',
'email' => 'email|nullable|unique:users,email',
];
break;
case 'PUT':
return [
'name' => 'required',
'addresses.*.address_street_1' => 'max:255',
'addresses.*.address_street_2' => 'max:255',
];
break;
default:

View File

@ -27,13 +27,22 @@ class EstimatesRequest extends FormRequest
'expiry_date' => 'required',
'estimate_number' => 'required|unique:estimates,estimate_number',
'user_id' => 'required',
'discount' => 'required',
'discount' => 'required|digits_between:1,20',
'discount_val' => 'required|digits_between:1,20',
'sub_total' => 'required|digits_between:1,20',
'total' => 'required|digits_between:1,20',
'tax' => 'required|digits_between:1,20',
'estimate_template_id' => 'required',
'items' => 'required|array',
'items.*.description' => 'max:255',
'items.*' => 'required|max:255',
'items.*.name' => 'required',
'items.*.quantity' => 'required|numeric',
'items.*.price' => 'required|numeric',
'items.*.quantity' => 'required|digits_between:1,20',
'items.*.price' => 'required|digits_between:1,20',
'items.*.discount' => 'digits_between:1,20',
'items.*.discount_val' => 'digits_between:1,20',
'items.*.tax' => 'digits_between:1,20',
'items.*.total' => 'digits_between:1,20',
];
if ($this->getMethod() == 'PUT') {

View File

@ -25,7 +25,7 @@ class ExpenseRequest extends FormRequest
return [
'expense_date' => 'required',
'expense_category_id' => 'required',
'amount' => 'required'
'amount' => 'required|digits_between:1,20'
];
}
}

View File

@ -27,13 +27,22 @@ class InvoicesRequest extends FormRequest
'due_date' => 'required',
'invoice_number' => 'required|unique:invoices,invoice_number',
'user_id' => 'required',
'discount' => 'required',
'discount' => 'required|digits_between:1,20',
'discount_val' => 'required|digits_between:1,20',
'sub_total' => 'required|digits_between:1,20',
'total' => 'required|digits_between:1,20',
'tax' => 'required|digits_between:1,20',
'invoice_template_id' => 'required',
'items' => 'required|array',
'items.*' => 'required|max:255',
'items.*.description' => 'max:255',
'items.*.name' => 'required',
'items.*.quantity' => 'required|numeric',
'items.*.price' => 'required|numeric',
'items.*.quantity' => 'required|digits_between:1,20',
'items.*.price' => 'required|digits_between:1,20',
'items.*.discount' => 'digits_between:1,20',
'items.*.discount_val' => 'digits_between:1,20',
'items.*.tax' => 'digits_between:1,20',
'items.*.total' => 'digits_between:1,20',
];
if ($this->getMethod() == 'PUT') {

View File

@ -24,7 +24,7 @@ class ItemsRequest extends FormRequest
{
return [
'name' => 'required',
'price' => 'required',
'price' => 'required|digits_between:1,20',
];
}
}

View File

@ -26,7 +26,7 @@ class PaymentRequest extends FormRequest
'payment_date' => 'required',
'payment_number' => 'required|unique:payments,payment_number',
'user_id' => 'required',
'amount' => 'required',
'amount' => 'required|digits_between:1,20',
];
if ($this->getMethod() == 'PUT') {

View File

@ -31,6 +31,8 @@ class ProfileRequest extends FormRequest
return [
'name' => 'required',
'password' => 'required',
'address_street_1' => 'max:255',
'address_street_2' => 'max:255',
'email' => [
'required',
'email',
@ -41,6 +43,8 @@ class ProfileRequest extends FormRequest
case 'PUT':
return [
'name' => 'required',
'address_street_1' => 'max:255',
'address_street_2' => 'max:255',
'email' => 'required|email'
];
break;

View File

@ -113,6 +113,19 @@ class Invoice extends Model
return $this->belongsTo(InvoiceTemplate::class);
}
public function getPreviousStatus()
{
if ($this->due_date < Carbon::now()) {
return self::STATUS_OVERDUE;
} elseif ($this->viewed) {
return self::STATUS_VIEWED;
} elseif ($this->sent) {
return self::STATUS_SENT;
} else {
return self::STATUS_DRAFT;
}
}
private function strposX($haystack, $needle, $number)
{
if ($number == '1') {

View File

@ -60,7 +60,7 @@ class InvoiceItem extends Model
$query->whereBetween(
'invoice_date',
[$start->format('Y-m-d'), $end->format('Y-m-d')]
)->where('paid_status', Invoice::STATUS_PAID);
);
});
}

View File

@ -0,0 +1,24 @@
<?php
namespace Laraspace\Listeners\Updates;
class Listener
{
const VERSION = '';
/**
* Check if should listen.
*
* @param $event
* @return boolean
*/
protected function check($event)
{
// Do not apply to the same or newer versions
// if (version_compare($event->old, static::VERSION, '>=')) {
// return false;
// }
return true;
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Laraspace\Listeners\Updates\V10;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Laraspace\Listeners\Updates\Listener;
use Laraspace\Events\UpdateFinished;
use Illuminate\Support\Facades\Artisan;
use Laraspace\Setting;
class Version101 extends Listener
{
const VERSION = '1.0.1';
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle(UpdateFinished $event)
{
// if (!$this->check($event)) {
// return;
// }
Artisan::call('db:seed', ['--class' => 'DemoSeeder', '--force' => true]);
Setting::getSetting('version', self::VERSION);
}
}

View File

@ -4,6 +4,8 @@ namespace Laraspace\Providers;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Laraspace\Events\UpdateFinished;
use Laraspace\Listeners\Updates\V10\Version101;
class EventServiceProvider extends ServiceProvider
{
@ -13,8 +15,8 @@ class EventServiceProvider extends ServiceProvider
* @var array
*/
protected $listen = [
'Laraspace\Events\SomeEvent' => [
'Laraspace\Listeners\EventListener',
UpdateFinished::class=> [
Version101::class,
],
Registered::class => [
SendEmailVerificationNotification::class,

36
app/Space/SiteApi.php Normal file
View File

@ -0,0 +1,36 @@
<?php
namespace Laraspace\Space;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Laraspace\Setting;
trait SiteApi
{
protected static function getRemote($url, $data = array())
{
$base = 'http://crater-main.test/';
$client = new Client(['verify' => false, 'base_uri' => $base]);
$headers['headers'] = array(
'Accept' => 'application/json',
'Referer' => url('/'),
'crater' => Setting::getSetting('version')
);
$data['http_errors'] = false;
$data = array_merge($data, $headers);
try {
$result = $client->get($url, $data);
} catch (RequestException $e) {
$result = $e;
}
return $result;
}
}

110
app/Space/Updater.php Normal file
View File

@ -0,0 +1,110 @@
<?php
namespace Laraspace\Space;
use File;
use ZipArchive;
use Artisan;
use GuzzleHttp\Exception\RequestException;
use Laraspace\Space\SiteApi;
use Laraspace\Events\UpdateFinished;
use Laraspace\Setting;
class Updater
{
use SiteApi;
public static function update($installed, $version)
{
$data = null;
$path = null;
$url = '/download/'.$version;
$response = static::getRemote($url, ['timeout' => 100, 'track_redirects' => true]);
// Exception
if ($response instanceof RequestException) {
return [
'success' => false,
'errors' => 'Download Exception',
'data' => [
'path' => $path
]
];
}
if ($response && ($response->getStatusCode() == 200)) {
$data = $response->getBody()->getContents();
}
// Create temp directory
$path = 'temp-' . md5(mt_rand());
$path2 = 'temp2-' . md5(mt_rand());
$temp_path = storage_path('app/temp') . '/' . $path;
$temp_path2 = storage_path('app/temp') . '/' . $path2;
if (!File::isDirectory($temp_path)) {
File::makeDirectory($temp_path);
File::makeDirectory($temp_path2);
}
$file = $temp_path . '/upload.zip';
// Add content to the Zip file
$uploaded = is_int(file_put_contents($file, $data)) ? true : false;
if (!$uploaded) {
return false;
}
// Unzip the file
$zip = new ZipArchive();
if ($zip->open($file)) {
$zip->extractTo($temp_path2);
}
$zip->close();
// Delete zip file
File::delete($file);
if (!File::copyDirectory($temp_path2.'/crater', base_path())) {
return false;
}
// Delete temp directory
File::deleteDirectory($temp_path);
File::deleteDirectory($temp_path2);
try {
event(new UpdateFinished($installed, $version));
return [
'success' => true,
'errors' => false,
'data' => []
];
} catch (\Exception $e) {
return [
'success' => false,
'errors' => 'Update error',
'data' => []
];
}
}
public static function checkForUpdate()
{
$data = null;
$url = '/check/latest/download/'.Setting::getSetting('version');
$response = static::getRemote($url, ['timeout' => 100, 'track_redirects' => true]);
if ($response && ($response->getStatusCode() == 200)) {
$data = $response->getBody()->getContents();
}
return json_decode($data);
}
}

View File

@ -216,7 +216,7 @@ class User extends Authenticatable implements HasMedia
$query->whereBetween(
'invoice_date',
[$start->format('Y-m-d'), $end->format('Y-m-d')]
)->where('paid_status', Invoice::STATUS_PAID);
);
});
}

View File

@ -18,7 +18,7 @@ class CreateItemsTable extends Migration
$table->string('name');
$table->string('description')->nullable();
$table->string('unit')->nullable();
$table->integer('price');
$table->unsignedBigInteger('price');
$table->integer('company_id')->unsigned()->nullable();
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$table->timestamps();

View File

@ -24,13 +24,13 @@ class CreateInvoicesTable extends Migration
$table->string('tax_per_item');
$table->string('discount_per_item');
$table->text('notes')->nullable();
$table->decimal('discount', 15, 0)->nullable();
$table->string('discount_type')->nullable();
$table->integer('discount_val')->nullable();
$table->integer('sub_total');
$table->integer('total');
$table->integer('tax');
$table->integer('due_amount');
$table->unsignedBigInteger('discount')->nullable();
$table->unsignedBigInteger('discount_val')->nullable();
$table->unsignedBigInteger('sub_total');
$table->unsignedBigInteger('total');
$table->unsignedBigInteger('tax');
$table->unsignedBigInteger('due_amount');
$table->boolean('sent')->default(false);
$table->boolean('viewed')->default(false);
$table->string('unique_hash')->nullable();

View File

@ -17,13 +17,13 @@ class CreateInvoiceItemsTable extends Migration
$table->increments('id');
$table->string('name');
$table->string('description')->nullable();
$table->integer('quantity');
$table->integer('price');
$table->string('discount_type');
$table->integer('discount_val');
$table->decimal('discount', 15, 0);
$table->integer('tax');
$table->integer('total');
$table->unsignedBigInteger('quantity');
$table->unsignedBigInteger('price');
$table->unsignedBigInteger('discount_val');
$table->unsignedBigInteger('discount');
$table->unsignedBigInteger('tax');
$table->unsignedBigInteger('total');
$table->integer('invoice_id')->unsigned();
$table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
$table->integer('item_id')->unsigned()->nullable();

View File

@ -23,12 +23,12 @@ class CreateEstimatesTable extends Migration
$table->string('tax_per_item');
$table->string('discount_per_item');
$table->string('notes')->nullable();
$table->decimal('discount', 15, 0)->nullable();
$table->string('discount_type')->nullable();
$table->integer('discount_val')->nullable();
$table->integer('sub_total');
$table->integer('total');
$table->integer('tax');
$table->unsignedBigInteger('discount')->nullable();
$table->unsignedBigInteger('discount_val')->nullable();
$table->unsignedBigInteger('sub_total');
$table->unsignedBigInteger('total');
$table->unsignedBigInteger('tax');
$table->string('unique_hash')->nullable();
$table->integer('user_id')->unsigned()->nullable();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

View File

@ -17,13 +17,13 @@ class CreateEstimateItemsTable extends Migration
$table->increments('id');
$table->string('name');
$table->string('description')->nullable();
$table->integer('quantity');
$table->string('discount_type');
$table->decimal('discount', 15, 0);
$table->integer('discount_val');
$table->integer('price');
$table->integer('tax');
$table->integer('total');
$table->unsignedBigInteger('quantity');
$table->unsignedBigInteger('discount');
$table->unsignedBigInteger('discount_val');
$table->unsignedBigInteger('price');
$table->unsignedBigInteger('tax');
$table->unsignedBigInteger('total');
$table->integer('item_id')->unsigned()->nullable();
$table->foreign('item_id')->references('id')->on('items')->onDelete('cascade');
$table->integer('estimate_id')->unsigned();

View File

@ -17,7 +17,7 @@ class CreateExpensesTable extends Migration
$table->increments('id');
$table->date('expense_date');
$table->string('attachment_receipt')->nullable();
$table->integer('amount');
$table->unsignedBigInteger('amount');
$table->string('notes')->nullable();
$table->integer('expense_category_id')->unsigned();
$table->foreign('expense_category_id')->references('id')->on('expense_categories')->onDelete('cascade');

View File

@ -19,7 +19,7 @@ class CreatePaymentsTable extends Migration
$table->string('payment_mode')->nullable();
$table->date('payment_date');
$table->text('notes')->nullable();
$table->decimal('amount', 15, 0);
$table->unsignedBigInteger('amount');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->integer('invoice_id')->unsigned()->nullable();

View File

@ -30,7 +30,7 @@ class CreateTaxesTable extends Migration
$table->integer('company_id')->unsigned()->nullable();
$table->foreign('company_id')->references('id')->on('companies');
$table->string('name');
$table->decimal('amount', 15, 0);
$table->unsignedBigInteger('amount');
$table->decimal('percent', 5, 2);
$table->tinyInteger('compound_tax')->default(0);
$table->timestamps();

View File

@ -13,19 +13,19 @@ class EstimateTemplateSeeder extends Seeder
public function run()
{
EstimateTemplate::create([
'name' => 'Estimate Template1',
'name' => 'Template 1',
'view' => 'estimate1',
'path' => '/assets/img/PDF/Template1.png'
]);
EstimateTemplate::create([
'name' => 'Estimate Template2',
'name' => 'Template 2',
'view' => 'estimate2',
'path' => '/assets/img/PDF/Template2.png'
]);
EstimateTemplate::create([
'name' => 'Estimate Template3',
'name' => 'Template 3',
'view' => 'estimate3',
'path' => '/assets/img/PDF/Template3.png'
]);

View File

@ -13,19 +13,19 @@ class InvoiceTemplateSeeder extends Seeder
public function run()
{
InvoiceTemplate::create([
'name' => 'Invoice Template1',
'name' => 'Template 1',
'view' => 'invoice1',
'path' => '/assets/img/PDF/Template1.png'
]);
InvoiceTemplate::create([
'name' => 'Invoice Template2',
'name' => ' Template 2',
'view' => 'invoice2',
'path' => '/assets/img/PDF/Template2.png'
]);
InvoiceTemplate::create([
'name' => 'Invoice Template3',
'name' => 'Template 3',
'view' => 'invoice3',
'path' => '/assets/img/PDF/Template3.png'
]);

View File

@ -1,6 +1,6 @@
<template>
<transition name="fade">
<div v-if="modalActive" class="base-modal" :class="'size-' + modalSize">
<div v-if="modalActive" :class="'size-' + modalSize" class="base-modal">
<div class="modal-body">
<div class="close-icon">
<font-awesome-icon class="mr-2" icon="times" @click="closeModal"/>

View File

@ -233,6 +233,8 @@ export default {
confirm_mark_as_accepted: 'This estimate will be marked as Accepted',
confirm_mark_as_rejected: 'This estimate will be marked as Rejected',
no_matching_estimates: 'There are no matching estimates!',
mark_as_sent_successfully: 'Estimate marked as sent successfully',
send_estimate_successfully: 'Estimate sent successfully',
errors: {
required: 'Field is required'
},
@ -324,6 +326,8 @@ export default {
list_of_invoices: 'This section will contain the list of invoices.',
select_invoice: 'Select Invoice',
no_matching_invoices: 'There are no matching invoices!',
mark_as_sent_successfully: 'Invoice marked as sent successfully',
send_invoice_successfully: 'Invoice sent successfully',
item: {
title: 'Item Title',
description: 'Description',

View File

@ -237,6 +237,8 @@ export default {
confirm_mark_as_sent: 'Esta estimación se marcará como enviada',
confirm_mark_as_accepted: 'Esta estimación se marcará como Aceptada',
confirm_mark_as_rejected: 'Esta estimación se marcará como Rechazada',
mark_as_sent_successfully: 'Estimación marcada como enviada correctamente',
send_estimate_successfully: 'Estimación enviada con éxito',
errors: {
required: 'Se requiere campo'
},
@ -326,6 +328,8 @@ export default {
no_invoices: '¡Aún no hay facturas!',
list_of_invoices: 'Esta sección contendrá la lista de facturas.',
select_invoice: 'Seleccionar factura',
mark_as_sent_successfully: 'Factura marcada como enviada con éxito',
send_invoice_successfully: 'Factura enviada exitosamente',
item: {
title: 'Título del artículo',
description: 'Descripción',

View File

@ -237,6 +237,8 @@ export default {
confirm_mark_as_sent: 'Cette estimation sera marquée comme envoyé',
confirm_mark_as_accepted: 'Cette estimation sera marquée comme acceptée',
confirm_mark_as_rejected: 'Cette estimation sera marquée comme Rejetée',
mark_as_sent_successfully: 'Estimation marquée comme envoyée avec succès',
send_estimate_successfully: 'Estimation envoyée avec succès',
errors: {
required: 'Champ requis'
},
@ -326,6 +328,8 @@ export default {
no_invoices: 'Aucune facture pour le moment!',
list_of_invoices: 'Cette section contiendra la liste des factures.',
select_invoice: 'Sélectionnez facture',
mark_as_sent_successfully: 'Facture marquée comme envoyée avec succès',
send_invoice_successfully: 'Facture envoyée avec succès',
item: {
title: 'Titre de larticle',
description: 'La description',

View File

@ -396,7 +396,7 @@ export default {
swal({
title: this.$t('general.are_you_sure'),
text: this.$tc('estimates.confirm_delete', 1),
icon: 'error',
icon: '/assets/icon/trash-solid.svg',
buttons: true,
dangerMode: true
}).then(async (willDelete) => {
@ -416,7 +416,7 @@ export default {
swal({
title: this.$t('general.are_you_sure'),
text: this.$t('estimates.confirm_conversion'),
icon: 'error',
icon: '/assets/icon/envelope-solid.svg',
buttons: true,
dangerMode: true
}).then(async (willDelete) => {
@ -433,14 +433,24 @@ export default {
})
},
async onMarkAsSent (id) {
swal({
title: this.$t('general.are_you_sure'),
text: this.$t('estimates.confirm_mark_as_sent'),
icon: '/assets/icon/check-circle-solid.svg',
buttons: true,
dangerMode: true
}).then(async (willMarkAsSent) => {
if (willMarkAsSent) {
const data = {
id: id
}
let response = await this.markAsSent(data)
this.$refs.table.refresh()
if (response.data) {
window.toastr['success'](this.$tc('estimates.mark_as_sent'))
window.toastr['success'](this.$tc('estimates.mark_as_sent_successfully'))
}
}
})
},
async removeInvoice (id) {
@ -448,7 +458,7 @@ export default {
swal({
title: this.$t('general.are_you_sure'),
text: this.$tc('invoices.confirm_delete'),
icon: 'error',
icon: '/assets/icon/trash-solid.svg',
buttons: true,
dangerMode: true
}).then(async (willDelete) => {
@ -465,25 +475,45 @@ export default {
},
async sendInvoice (id) {
swal({
title: this.$t('general.are_you_sure'),
text: this.$t('invoices.confirm_send'),
icon: '/assets/icon/paper-plane-solid.svg',
buttons: true,
dangerMode: true
}).then(async (willSendInvoice) => {
if (willSendInvoice) {
const data = {
id: id
}
let response = await this.sendEmail(data)
this.$refs.table.refresh()
if (response.data) {
window.toastr['success'](this.$tc('invoices.send_invoice'))
window.toastr['success'](this.$tc('invoices.send_invoice_successfully'))
}
}
})
},
async sentInvoice (id) {
swal({
title: this.$t('general.are_you_sure'),
text: this.$t('invoices.invoice_mark_as_sent'),
icon: '/assets/icon/check-circle-solid.svg',
buttons: true,
dangerMode: true
}).then(async (willMarkAsSend) => {
if (willMarkAsSend) {
const data = {
id: id
}
let response = await this.markAsSent(data)
this.$refs.table.refresh()
if (response.data) {
window.toastr['success'](this.$tc('invoices.mark_as_sent'))
window.toastr['success'](this.$tc('invoices.mark_as_sent_successfully'))
}
}
})
}
}
}

View File

@ -425,7 +425,7 @@ export default {
if (response.data) {
this.filters.status = 'ACCEPTED'
this.$refs.table.refresh()
window.toastr['success'](this.$tc('estimates.marked_as_rejected_message'))
window.toastr['success'](this.$tc('estimates.confirm_mark_as_accepted'))
}
}
})
@ -570,7 +570,7 @@ export default {
let response = await this.markAsSent(data)
this.refreshTable()
if (response.data) {
window.toastr['success'](this.$tc('estimates.mark_as_sent'))
window.toastr['success'](this.$tc('estimates.mark_as_sent_successfully'))
}
}
})
@ -590,7 +590,7 @@ export default {
let response = await this.sendEmail(data)
this.refreshTable()
if (response.data) {
window.toastr['success'](this.$tc('estimates.mark_as_sent'))
window.toastr['success'](this.$tc('estimates.send_estimate_successfully'))
}
}
})

View File

@ -5,6 +5,7 @@
<div class="page-actions row">
<div class="col-xs-2">
<base-button
v-if="estimate.status !== 'SENT'"
:loading="isRequestOnGoing"
:disabled="isRequestOnGoing"
:outline="true"
@ -33,7 +34,7 @@
</v-dropdown>
</div>
</div>
<div class="estimate-sidebar">
<div class="estimate-si debar">
<base-loader v-if="isSearching" />
<div v-else class="side-header">
<base-input
@ -144,6 +145,8 @@ export default {
orderByField: null,
searchText: null
},
status: ['DRAFT', 'SENT', 'VIEWED', 'EXPIRED', 'ACCEPTED', 'REJECTED'],
isMarkAsSent: false,
isRequestOnGoing: false,
isSearching: false
}
@ -230,11 +233,11 @@ export default {
dangerMode: true
}).then(async (willMarkAsSent) => {
if (willMarkAsSent) {
this.isRequestOnGoing = true
this.isMarkAsSent = true
let response = await this.markAsSent({id: this.estimate.id})
this.isRequestOnGoing = false
this.isMarkAsSent = false
if (response.data) {
window.toastr['success'](this.$tc('estimates.mark_as_sent'))
window.toastr['success'](this.$tc('estimates.mark_as_sent_successfully'))
}
}
})

View File

@ -390,15 +390,15 @@ export default {
icon: '/assets/icon/paper-plane-solid.svg',
buttons: true,
dangerMode: true
}).then(async (Send_Invoice) => {
if (Send_Invoice) {
}).then(async (willSendInvoice) => {
if (willSendInvoice) {
const data = {
id: id
}
let response = await this.sendEmail(data)
this.refreshTable()
if (response.data) {
window.toastr['success'](this.$tc('invoices.send_invoice'))
window.toastr['success'](this.$tc('invoices.send_invoice_successfully'))
}
}
})
@ -410,15 +410,15 @@ export default {
icon: '/assets/icon/check-circle-solid.svg',
buttons: true,
dangerMode: true
}).then(async (MarkAsSend_Invoice) => {
if (MarkAsSend_Invoice) {
}).then(async (willMarkAsSend) => {
if (willMarkAsSend) {
const data = {
id: id
}
let response = await this.markAsSent(data)
this.refreshTable()
if (response.data) {
window.toastr['success'](this.$tc('invoices.mark_as_sent'))
window.toastr['success'](this.$tc('invoices.mark_as_sent_successfully'))
}
}
})

View File

@ -263,7 +263,7 @@
}
tr.main-table-header th {
border-bottom: 1px solid #EAF1FB;
border-bottom: 0.620315px solid #E8E8E8;
font-style: normal;
font-weight: normal;
font-size: 12px;

View File

@ -264,7 +264,7 @@
}
tr.main-table-header th {
border-bottom: 1px solid #EAF1FB;
border-bottom: 0.620315px solid #E8E8E8;
font-style: normal;
font-weight: normal;
font-size: 12px;

View File

@ -1,6 +1,8 @@
<div class="notes">
@if ($estimate->notes != '' && $estimate->notes != null)
<div class="notes">
<div class="notes-label">
Notes
</div>
{{$estimate->notes}}
</div>
</div>
@endif

View File

@ -1,27 +1,32 @@
<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: left; color: #55547A; padding-left: 40px">Price</th>
<th width="18%" class="ItemTableHeader" style="text-align: right; color: #55547A; padding-right: 40px">Price</th>
@if($estimate->discount_per_item === 'YES')
<th width="10%" class="ItemTableHeader" style="text-align: left; color: #55547A; padding-left: 10px">Discount</th>
<th width="10%" 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>
</tr>
@php
$index = 1
@endphp
@foreach ($estimate->items as $item)
<tr class="item-details">
<td class="inv-item items" style="text-align: right; color: #040405; padding-right: 20px; vertical-align: top;">{{$index}}</td>
<td class="inv-item items" style="text-align: left; color: #040405;padding-left: 0px">
<span>{{ $item->name }}</span><br>
<span style="text-align: left; color: #595959; font-size: 9px; font-weight:300; line-height: 12px;">{{ $item->description }}</span>
</td>
<td class="inv-item items" style="text-align: right; color: #040405; padding-right: 20px">{{$item->quantity}}</td>
<td class="inv-item items" style="text-align: left; color: #040405; padding-left: 40px">{{$item->price/100}}</td>
<td class="inv-item items" style="text-align: right; color: #040405; padding-right: 40px">{{$item->price/100}}</td>
@if($estimate->discount_per_item === 'YES')
<td class="inv-item items" style="text-align: left; color: #040405; padding-left: 10px">
<td class="inv-item items" style="text-align: right; color: #040405; padding-left: 10px">
@if($item->discount_type === 'fixed')
{{$item->discount_val/100}}
@endif
@ -30,12 +35,15 @@
@endif
</td>
@endif
<td class="inv-item items" style="text-align: right; color: #040405">{{$item->total/100}}</td>
<td class="inv-item items" style="text-align: right; color: #040405;">{{$item->total/100}}</td>
</tr>
@php
$index += 1
@endphp
@endforeach
</table>
<table width="100%" style="margin-left:420px" cellspacing="0px" border="0" class="table3">
<table width="100%" cellspacing="0px" style="margin-left:420px" 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"

View File

@ -11,6 +11,7 @@
html {
margin: 0px;
padding: 0px;
margin-top: 50px;
}
table {
@ -35,7 +36,7 @@
width: 100%;
height: 90px;
left: 0px;
top: 0px;
top: -50px;
}
.header-logo {
@ -71,7 +72,7 @@
.wrapper {
display: block;
padding-top: 60px;
padding-top: 16px;
padding-bottom: 60px;
}
@ -251,6 +252,7 @@
page-break-after: auto;
}
.table2 hr {
height:0.1px;
}
@ -263,7 +265,7 @@
}
tr.main-table-header th {
border-bottom: 1px solid #EAF1FB;
border-bottom: 0.620315px solid #E8E8E8;
font-style: normal;
font-weight: normal;
font-size: 12px;
@ -380,8 +382,8 @@
</td>
</tr>
</table>
<hr class="header-line" style="border: 0.620315px solid #E8E8E8;"/>
</div>
<hr class="header-line" />
<div class="wrapper">
<div class="address">
<div class="company">

View File

@ -264,7 +264,7 @@
}
tr.main-table-header th {
border-bottom: 1px solid #EAF1FB;
border-bottom: 0.620315px solid #E8E8E8;
font-style: normal;
font-weight: normal;
font-size: 12px;

View File

@ -1,6 +1,8 @@
<div class="notes">
@if ($invoice->notes != '' && $invoice->notes != null)
<div class="notes">
<div class="notes-label">
Notes
</div>
{{$invoice->notes}}
</div>
</div>
@endif

View File

@ -1,27 +1,32 @@
<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($invoice->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: left; color: #55547A; padding-left: 40px">Price</th>
<th width="18%" class="ItemTableHeader" style="text-align: right; color: #55547A; padding-right: 40px">Price</th>
@if($invoice->discount_per_item === 'YES')
<th width="10%" class="ItemTableHeader" style="text-align: left; color: #55547A; padding-left: 10px">Discount</th>
<th width="10%" 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>
</tr>
@php
$index = 1
@endphp
@foreach ($invoice->items as $item)
<tr class="item-details">
<td class="inv-item items" style="text-align: right; color: #040405; padding-right: 20px; vertical-align: top;">{{$index}}</td>
<td class="inv-item items" style="text-align: left; color: #040405;padding-left: 0px">
<span>{{ $item->name }}</span><br>
<span style="text-align: left; color: #595959; font-size: 9px; font-weight:300; line-height: 12px;">{{ $item->description }}</span>
</td>
<td class="inv-item items" style="text-align: right; color: #040405; padding-right: 20px">{{$item->quantity}}</td>
<td class="inv-item items" style="text-align: left; color: #040405; padding-left: 40px">{{$item->price/100}}</td>
<td class="inv-item items" style="text-align: right; color: #040405; padding-right: 40px">{{$item->price/100}}</td>
@if($invoice->discount_per_item === 'YES')
<td class="inv-item items" style="text-align: left; color: #040405; padding-left: 10px">
<td class="inv-item items" style="text-align: right; color: #040405; padding-left: 10px">
@if($item->discount_type === 'fixed')
{{$item->discount_val/100}}
@endif
@ -30,8 +35,11 @@
@endif
</td>
@endif
<td class="inv-item items" style="text-align: right; color: #040405">{{$item->total/100}}</td>
<td class="inv-item items" style="text-align: right; color: #040405;">{{$item->total/100}}</td>
</tr>
@php
$index += 1
@endphp
@endforeach
</table>

View File

@ -106,6 +106,8 @@ Route::group(['middleware' => 'redirect-if-installed'], function () {
'uses' => 'OnboardingController@companySettings'
]);
});
// App version
// ----------------------------------
@ -120,6 +122,18 @@ Route::group(['middleware' => 'api'], function () {
'middleware' => 'admin'
], function () {
// Auto update routes
//----------------------------------
Route::post('/update', [
'as' => 'auto.update',
'uses' => 'UpdateController@update'
]);
Route::get('/check/update', [
'as' => 'check.update',
'uses' => 'UpdateController@checkLatestVersion'
]);
Route::get('/bootstrap', [
'as' => 'bootstrap',
'uses' => 'UsersController@getBootstrap'