mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-27 11:41:09 -04:00
Add Resend Email Option
This commit is contained in:
@ -1,16 +1,16 @@
|
||||
export default {
|
||||
toggleSidebar () {
|
||||
toggleSidebar() {
|
||||
let icon = document.getElementsByClassName('hamburger')[0]
|
||||
document.body.classList.toggle('sidebar-open')
|
||||
icon.classList.toggle('is-active')
|
||||
},
|
||||
|
||||
addClass (el, className) {
|
||||
addClass(el, className) {
|
||||
if (el.classList) el.classList.add(className)
|
||||
else el.className += ' ' + className
|
||||
},
|
||||
|
||||
hasClass (el, className) {
|
||||
hasClass(el, className) {
|
||||
const hasClass = el.classList
|
||||
? el.classList.contains(className)
|
||||
: new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className)
|
||||
@ -18,33 +18,38 @@ export default {
|
||||
return hasClass
|
||||
},
|
||||
|
||||
reset (prefix) {
|
||||
reset(prefix) {
|
||||
let regx = new RegExp('\\b' + prefix + '(.*)?\\b', 'g')
|
||||
document.body.className = document.body.className.replace(regx, '')
|
||||
},
|
||||
|
||||
setLayout (layoutName) {
|
||||
setLayout(layoutName) {
|
||||
this.reset('layout-')
|
||||
document.body.classList.add('layout-' + layoutName)
|
||||
},
|
||||
|
||||
setSkin (skinName) {
|
||||
setSkin(skinName) {
|
||||
this.reset('skin-')
|
||||
document.body.classList.add('skin-' + skinName)
|
||||
},
|
||||
|
||||
setLogo (logoSrc) {
|
||||
setLogo(logoSrc) {
|
||||
document.getElementById('logo-desk').src = logoSrc
|
||||
},
|
||||
|
||||
formatMoney (amount, currency = 0) {
|
||||
formatMoney(amount, currency = 0) {
|
||||
if (!currency) {
|
||||
currency = {precision: 2, thousand_separator: ',', decimal_separator: '.', symbol: '$'}
|
||||
currency = {
|
||||
precision: 2,
|
||||
thousand_separator: ',',
|
||||
decimal_separator: '.',
|
||||
symbol: '$',
|
||||
}
|
||||
}
|
||||
|
||||
amount = amount / 100
|
||||
|
||||
let {precision, decimal_separator, thousand_separator, symbol} = currency
|
||||
let { precision, decimal_separator, thousand_separator, symbol } = currency
|
||||
|
||||
try {
|
||||
precision = Math.abs(precision)
|
||||
@ -52,25 +57,44 @@ export default {
|
||||
|
||||
const negativeSign = amount < 0 ? '-' : ''
|
||||
|
||||
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(precision)).toString()
|
||||
let j = (i.length > 3) ? i.length % 3 : 0
|
||||
let i = parseInt(
|
||||
(amount = Math.abs(Number(amount) || 0).toFixed(precision))
|
||||
).toString()
|
||||
let j = i.length > 3 ? i.length % 3 : 0
|
||||
|
||||
let moneySymbol = `<span style="font-family: sans-serif">${symbol}</span>`
|
||||
|
||||
return moneySymbol + ' ' + negativeSign + (j ? i.substr(0, j) + thousand_separator : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand_separator) + (precision ? decimal_separator + Math.abs(amount - i).toFixed(precision).slice(2) : '')
|
||||
return (
|
||||
moneySymbol +
|
||||
' ' +
|
||||
negativeSign +
|
||||
(j ? i.substr(0, j) + thousand_separator : '') +
|
||||
i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand_separator) +
|
||||
(precision
|
||||
? decimal_separator +
|
||||
Math.abs(amount - i)
|
||||
.toFixed(precision)
|
||||
.slice(2)
|
||||
: '')
|
||||
)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
|
||||
formatGraphMoney (amount, currency = 0) {
|
||||
formatGraphMoney(amount, currency = 0) {
|
||||
if (!currency) {
|
||||
currency = {precision: 2, thousand_separator: ',', decimal_separator: '.', symbol: '$'}
|
||||
currency = {
|
||||
precision: 2,
|
||||
thousand_separator: ',',
|
||||
decimal_separator: '.',
|
||||
symbol: '$',
|
||||
}
|
||||
}
|
||||
|
||||
amount = amount / 100
|
||||
|
||||
let {precision, decimal_separator, thousand_separator, symbol} = currency
|
||||
let { precision, decimal_separator, thousand_separator, symbol } = currency
|
||||
|
||||
try {
|
||||
precision = Math.abs(precision)
|
||||
@ -78,25 +102,76 @@ export default {
|
||||
|
||||
const negativeSign = amount < 0 ? '-' : ''
|
||||
|
||||
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(precision)).toString()
|
||||
let j = (i.length > 3) ? i.length % 3 : 0
|
||||
let i = parseInt(
|
||||
(amount = Math.abs(Number(amount) || 0).toFixed(precision))
|
||||
).toString()
|
||||
let j = i.length > 3 ? i.length % 3 : 0
|
||||
|
||||
let moneySymbol = `${symbol}`
|
||||
|
||||
return moneySymbol + ' ' + negativeSign + (j ? i.substr(0, j) + thousand_separator : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand_separator) + (precision ? decimal_separator + Math.abs(amount - i).toFixed(precision).slice(2) : '')
|
||||
return (
|
||||
moneySymbol +
|
||||
' ' +
|
||||
negativeSign +
|
||||
(j ? i.substr(0, j) + thousand_separator : '') +
|
||||
i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousand_separator) +
|
||||
(precision
|
||||
? decimal_separator +
|
||||
Math.abs(amount - i)
|
||||
.toFixed(precision)
|
||||
.slice(2)
|
||||
: '')
|
||||
)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
|
||||
checkValidUrl (url) {
|
||||
let pattern = new RegExp('^(https?:\\/\\/)?' + // protocol
|
||||
checkValidUrl(url) {
|
||||
let pattern = new RegExp(
|
||||
'^(https?:\\/\\/)?' + // protocol
|
||||
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
|
||||
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
|
||||
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
|
||||
'(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
|
||||
'(\\#[-a-z\\d_]*)?$', 'i') // fragment locator
|
||||
'(\\#[-a-z\\d_]*)?$',
|
||||
'i'
|
||||
) // fragment locator
|
||||
|
||||
return !!pattern.test(url)
|
||||
}
|
||||
},
|
||||
|
||||
fallbackCopyTextToClipboard(text) {
|
||||
var textArea = document.createElement('textarea')
|
||||
textArea.value = text
|
||||
// Avoid scrolling to bottom
|
||||
textArea.style.top = '0'
|
||||
textArea.style.left = '0'
|
||||
textArea.style.position = 'fixed'
|
||||
document.body.appendChild(textArea)
|
||||
textArea.focus()
|
||||
textArea.select()
|
||||
try {
|
||||
var successful = document.execCommand('copy')
|
||||
var msg = successful ? 'successful' : 'unsuccessful'
|
||||
console.log('Fallback: Copying text command was ' + msg)
|
||||
} catch (err) {
|
||||
console.error('Fallback: Oops, unable to copy', err)
|
||||
}
|
||||
document.body.removeChild(textArea)
|
||||
},
|
||||
copyTextToClipboard(text) {
|
||||
if (!navigator.clipboard) {
|
||||
this.fallbackCopyTextToClipboard(text)
|
||||
return
|
||||
}
|
||||
navigator.clipboard.writeText(text).then(
|
||||
function () {
|
||||
return true
|
||||
},
|
||||
function (err) {
|
||||
return false
|
||||
}
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
},
|
||||
"general": {
|
||||
"view_pdf": "View PDF",
|
||||
"copy_pdf_url": "Copy PDF Url",
|
||||
"download_pdf": "Download PDF",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
@ -230,6 +231,7 @@
|
||||
"convert_to_invoice": "Convert to Invoice",
|
||||
"mark_as_sent": "Mark as Sent",
|
||||
"send_estimate": "Send Estimate",
|
||||
"resend_estimate": "Resend Estimate",
|
||||
"record_payment": "Record Payment",
|
||||
"add_estimate": "Add Estimate",
|
||||
"save_estimate": "Save Estimate",
|
||||
@ -316,6 +318,7 @@
|
||||
"notes": "Notes",
|
||||
"view": "View",
|
||||
"send_invoice": "Send Invoice",
|
||||
"resend_invoice": "Resend Invoice",
|
||||
"invoice_template": "Invoice Template",
|
||||
"template": "Template",
|
||||
"mark_as_sent": "Mark as sent",
|
||||
@ -618,85 +621,85 @@
|
||||
"updated_message": "Company information updated successfully"
|
||||
},
|
||||
"customization": {
|
||||
"customization": "customization",
|
||||
"save": "Save",
|
||||
"addresses": {
|
||||
"title": "Addresses",
|
||||
"section_description": "You can set Customer Billing Address and Customer Shipping Address Format (Displayed in PDF only). ",
|
||||
"customer_billing_address": "Customer Billing Address",
|
||||
"customer_shipping_address": "Customer Shipping Address",
|
||||
"company_address": "Company Address",
|
||||
"insert_fields": "Insert Fields",
|
||||
"contact": "Contact",
|
||||
"address": "Address",
|
||||
"display_name": "Display Name",
|
||||
"primary_contact_name": "Primary Contact Name",
|
||||
"email": "Email",
|
||||
"website": "Website",
|
||||
"name": "Name",
|
||||
"country": "Country",
|
||||
"state": "State",
|
||||
"city": "City",
|
||||
"company_name": "Company Name",
|
||||
"address_street_1": "Address Street 1",
|
||||
"address_street_2": "Address Street 2",
|
||||
"phone": "Phone",
|
||||
"zip_code": "Zip Code",
|
||||
"address_setting_updated": "Address Setting updated successfully"
|
||||
},
|
||||
"updated_message": "Company information updated successfully",
|
||||
"customization": "customization",
|
||||
"save": "Save",
|
||||
"addresses": {
|
||||
"title": "Addresses",
|
||||
"section_description": "You can set Customer Billing Address and Customer Shipping Address Format (Displayed in PDF only). ",
|
||||
"customer_billing_address": "Customer Billing Address",
|
||||
"customer_shipping_address": "Customer Shipping Address",
|
||||
"company_address": "Company Address",
|
||||
"insert_fields": "Insert Fields",
|
||||
"contact": "Contact",
|
||||
"address": "Address",
|
||||
"display_name": "Display Name",
|
||||
"primary_contact_name": "Primary Contact Name",
|
||||
"email": "Email",
|
||||
"website": "Website",
|
||||
"name": "Name",
|
||||
"country": "Country",
|
||||
"state": "State",
|
||||
"city": "City",
|
||||
"company_name": "Company Name",
|
||||
"address_street_1": "Address Street 1",
|
||||
"address_street_2": "Address Street 2",
|
||||
"phone": "Phone",
|
||||
"zip_code": "Zip Code",
|
||||
"address_setting_updated": "Address Setting updated successfully"
|
||||
},
|
||||
"updated_message": "Company information updated successfully",
|
||||
|
||||
"invoices": {
|
||||
"title": "Invoices",
|
||||
"notes": "Notes",
|
||||
"invoice_prefix": "Invoice Prefix",
|
||||
"invoice_settings": "Invoice Settings",
|
||||
"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",
|
||||
"invoice_setting_updated": "Invoice Setting updated successfully"
|
||||
},
|
||||
"invoices": {
|
||||
"title": "Invoices",
|
||||
"notes": "Notes",
|
||||
"invoice_prefix": "Invoice Prefix",
|
||||
"invoice_settings": "Invoice Settings",
|
||||
"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",
|
||||
"invoice_setting_updated": "Invoice Setting updated successfully"
|
||||
},
|
||||
|
||||
"estimates": {
|
||||
"title": "Estimates",
|
||||
"estimate_prefix": "Estimate Prefix",
|
||||
"estimate_settings": "Estimate Settings",
|
||||
"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"
|
||||
},
|
||||
"estimates": {
|
||||
"title": "Estimates",
|
||||
"estimate_prefix": "Estimate Prefix",
|
||||
"estimate_settings": "Estimate Settings",
|
||||
"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"
|
||||
},
|
||||
|
||||
"payments": {
|
||||
"title": "Payments",
|
||||
"payment_prefix": "Payment Prefix",
|
||||
"payment_settings": "Payment Settings",
|
||||
"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_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"
|
||||
},
|
||||
"payments": {
|
||||
"title": "Payments",
|
||||
"payment_prefix": "Payment Prefix",
|
||||
"payment_settings": "Payment Settings",
|
||||
"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_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"
|
||||
}
|
||||
"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": {
|
||||
"profile_picture": "Profile Picture",
|
||||
|
||||
@ -4,16 +4,12 @@
|
||||
<h3 class="page-title">{{ $t('estimates.title') }}</h3>
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item">
|
||||
<router-link
|
||||
slot="item-title"
|
||||
to="dashboard">
|
||||
<router-link slot="item-title" to="dashboard">
|
||||
{{ $t('general.home') }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<router-link
|
||||
slot="item-title"
|
||||
to="#">
|
||||
<router-link slot="item-title" to="#">
|
||||
{{ $tc('estimates.estimate', 2) }}
|
||||
</router-link>
|
||||
</li>
|
||||
@ -33,11 +29,9 @@
|
||||
</base-button>
|
||||
</div>
|
||||
<router-link slot="item-title" class="col-xs-2" to="estimates/create">
|
||||
<base-button
|
||||
size="large"
|
||||
icon="plus"
|
||||
color="theme" >
|
||||
{{ $t('estimates.new_estimate') }}</base-button>
|
||||
<base-button size="large" icon="plus" color="theme">
|
||||
{{ $t('estimates.new_estimate') }}</base-button
|
||||
>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
@ -46,7 +40,7 @@
|
||||
<div v-show="showFilters" class="filter-section">
|
||||
<div class="filter-container">
|
||||
<div class="filter-customer">
|
||||
<label>{{ $tc('customers.customer',1) }} </label>
|
||||
<label>{{ $tc('customers.customer', 1) }} </label>
|
||||
<base-customer-select
|
||||
ref="customerSelect"
|
||||
@select="onSelectCustomer"
|
||||
@ -85,21 +79,28 @@
|
||||
</div>
|
||||
<div class="filter-estimate">
|
||||
<label>{{ $t('estimates.estimate_number') }}</label>
|
||||
<base-input
|
||||
v-model="filters.estimate_number"
|
||||
icon="hashtag"/>
|
||||
<base-input v-model="filters.estimate_number" icon="hashtag" />
|
||||
</div>
|
||||
</div>
|
||||
<label class="clear-filter" @click="clearFilter">{{ $t('general.clear_all') }}</label>
|
||||
<label class="clear-filter" @click="clearFilter">{{
|
||||
$t('general.clear_all')
|
||||
}}</label>
|
||||
</div>
|
||||
</transition>
|
||||
<div v-cloak v-show="showEmptyScreen" class="col-xs-1 no-data-info" align="center">
|
||||
<moon-walker-icon class="mt-5 mb-4"/>
|
||||
<div
|
||||
v-cloak
|
||||
v-show="showEmptyScreen"
|
||||
class="col-xs-1 no-data-info"
|
||||
align="center"
|
||||
>
|
||||
<moon-walker-icon class="mt-5 mb-4" />
|
||||
<div class="row" align="center">
|
||||
<label class="col title">{{ $t('estimates.no_estimates') }}</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="description col mt-1" align="center">{{ $t('estimates.list_of_estimates') }}</label>
|
||||
<label class="description col mt-1" align="center">{{
|
||||
$t('estimates.list_of_estimates')
|
||||
}}</label>
|
||||
</div>
|
||||
<div class="btn-container">
|
||||
<base-button
|
||||
@ -116,28 +117,57 @@
|
||||
|
||||
<div v-show="!showEmptyScreen" class="table-container">
|
||||
<div class="table-actions mt-5">
|
||||
<p class="table-stats">{{ $t('general.showing') }}: <b>{{ estimates.length }}</b> {{ $t('general.of') }} <b>{{ totalEstimates }}</b></p>
|
||||
<p class="table-stats">
|
||||
{{ $t('general.showing') }}: <b>{{ estimates.length }}</b>
|
||||
{{ $t('general.of') }} <b>{{ totalEstimates }}</b>
|
||||
</p>
|
||||
|
||||
<!-- Tabs -->
|
||||
<ul class="tabs">
|
||||
<li class="tab" @click="getStatus('DRAFT')">
|
||||
<a :class="['tab-link', {'a-active': filters.status === 'DRAFT'}]" href="#">{{ $t('general.draft') }}</a>
|
||||
<a
|
||||
:class="['tab-link', { 'a-active': filters.status === 'DRAFT' }]"
|
||||
href="#"
|
||||
>{{ $t('general.draft') }}</a
|
||||
>
|
||||
</li>
|
||||
<li class="tab" @click="getStatus('SENT')">
|
||||
<a :class="['tab-link', {'a-active': filters.status === 'SENT'}]" href="#" >{{ $t('general.sent') }}</a>
|
||||
<a
|
||||
:class="['tab-link', { 'a-active': filters.status === 'SENT' }]"
|
||||
href="#"
|
||||
>{{ $t('general.sent') }}</a
|
||||
>
|
||||
</li>
|
||||
<li class="tab" @click="getStatus('')">
|
||||
<a :class="['tab-link', {'a-active': filters.status === '' || filters.status !== 'DRAFT' && filters.status !== 'SENT'}]" href="#">{{ $t('general.all') }}</a>
|
||||
<a
|
||||
:class="[
|
||||
'tab-link',
|
||||
{
|
||||
'a-active':
|
||||
filters.status === '' ||
|
||||
(filters.status !== 'DRAFT' && filters.status !== 'SENT'),
|
||||
},
|
||||
]"
|
||||
href="#"
|
||||
>{{ $t('general.all') }}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<transition name="fade">
|
||||
<v-dropdown v-if="selectedEstimates.length" :show-arrow="false">
|
||||
<span slot="activator" href="#" class="table-actions-button dropdown-toggle">
|
||||
<span
|
||||
slot="activator"
|
||||
href="#"
|
||||
class="table-actions-button dropdown-toggle"
|
||||
>
|
||||
{{ $t('general.actions') }}
|
||||
</span>
|
||||
<v-dropdown-item>
|
||||
<div class="dropdown-item" @click="removeMultipleEstimates">
|
||||
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'trash']"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('general.delete') }}
|
||||
</div>
|
||||
</v-dropdown-item>
|
||||
@ -153,8 +183,12 @@
|
||||
type="checkbox"
|
||||
class="custom-control-input"
|
||||
@change="selectAllEstimates"
|
||||
/>
|
||||
<label
|
||||
v-show="!isRequestOngoing"
|
||||
for="select-all"
|
||||
class="custom-control-label selectall"
|
||||
>
|
||||
<label v-show="!isRequestOngoing" for="select-all" class="custom-control-label selectall">
|
||||
<span class="select-all-label">{{ $t('general.select_all') }} </span>
|
||||
</label>
|
||||
</div>
|
||||
@ -178,7 +212,7 @@
|
||||
:value="row.id"
|
||||
type="checkbox"
|
||||
class="custom-control-input"
|
||||
>
|
||||
/>
|
||||
<label :for="row.id" class="custom-control-label" />
|
||||
</div>
|
||||
</template>
|
||||
@ -186,30 +220,30 @@
|
||||
<table-column
|
||||
:label="$t('estimates.date')"
|
||||
sort-as="estimate_date"
|
||||
show="formattedEstimateDate" />
|
||||
show="formattedEstimateDate"
|
||||
/>
|
||||
<table-column
|
||||
:label="$t('estimates.customer')"
|
||||
sort-as="name"
|
||||
show="name" />
|
||||
show="name"
|
||||
/>
|
||||
<!-- <table-column
|
||||
:label="$t('estimates.expiry_date')"
|
||||
sort-as="expiry_date"
|
||||
show="formattedExpiryDate" /> -->
|
||||
<table-column
|
||||
:label="$t('estimates.status')"
|
||||
show="status" >
|
||||
<template slot-scope="row" >
|
||||
<table-column :label="$t('estimates.status')" show="status">
|
||||
<template slot-scope="row">
|
||||
<span> {{ $t('estimates.status') }}</span>
|
||||
<span :class="'est-status-'+row.status.toLowerCase()">{{ row.status }}</span>
|
||||
<span :class="'est-status-' + row.status.toLowerCase()">{{
|
||||
row.status
|
||||
}}</span>
|
||||
</template>
|
||||
</table-column>
|
||||
<table-column
|
||||
:label="$tc('estimates.estimate', 1)"
|
||||
show="estimate_number"/>
|
||||
<table-column
|
||||
:label="$t('invoices.total')"
|
||||
sort-as="total"
|
||||
>
|
||||
show="estimate_number"
|
||||
/>
|
||||
<table-column :label="$t('invoices.total')" sort-as="total">
|
||||
<template slot-scope="row">
|
||||
<span> {{ $t('estimates.total') }}</span>
|
||||
<div v-html="$utils.formatMoney(row.total, row.user.currency)" />
|
||||
@ -227,50 +261,114 @@
|
||||
<dot-icon />
|
||||
</a>
|
||||
<v-dropdown-item>
|
||||
<router-link :to="{path: `estimates/${row.id}/edit`}" class="dropdown-item">
|
||||
<font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon" />
|
||||
<router-link
|
||||
:to="{ path: `estimates/${row.id}/edit` }"
|
||||
class="dropdown-item"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'pencil-alt']"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('general.edit') }}
|
||||
</router-link>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item>
|
||||
<div class="dropdown-item" @click="removeEstimate(row.id)">
|
||||
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'trash']"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('general.delete') }}
|
||||
</div>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item>
|
||||
<router-link :to="{path: `estimates/${row.id}/view`}" class="dropdown-item">
|
||||
<router-link
|
||||
:to="{ path: `estimates/${row.id}/view` }"
|
||||
class="dropdown-item"
|
||||
>
|
||||
<font-awesome-icon icon="eye" class="dropdown-item-icon" />
|
||||
{{ $t('general.view') }}
|
||||
</router-link>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item>
|
||||
<a class="dropdown-item" href="#/" @click="convertInToinvoice(row.id)">
|
||||
<font-awesome-icon icon="file-alt" class="dropdown-item-icon" />
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#/"
|
||||
@click="convertInToinvoice(row.id)"
|
||||
>
|
||||
<font-awesome-icon
|
||||
icon="file-alt"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('estimates.convert_to_invoice') }}
|
||||
</a>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item v-if="row.status !== 'SENT'">
|
||||
<a class="dropdown-item" href="#/" @click.self="onMarkAsSent(row.id)">
|
||||
<font-awesome-icon icon="check-circle" class="dropdown-item-icon" />
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#/"
|
||||
@click.self="onMarkAsSent(row.id)"
|
||||
>
|
||||
<font-awesome-icon
|
||||
icon="check-circle"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('estimates.mark_as_sent') }}
|
||||
</a>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item v-if="row.status !== 'SENT'">
|
||||
<a class="dropdown-item" href="#/" @click.self="sendEstimate(row.id)">
|
||||
<font-awesome-icon icon="paper-plane" class="dropdown-item-icon" />
|
||||
<v-dropdown-item v-if="row.status === 'DRAFT'">
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#/"
|
||||
@click.self="sendEstimate(row.id)"
|
||||
>
|
||||
<font-awesome-icon
|
||||
icon="paper-plane"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('estimates.send_estimate') }}
|
||||
</a>
|
||||
</v-dropdown-item>
|
||||
<!-- resend estimte -->
|
||||
<v-dropdown-item
|
||||
v-if="row.status == 'SENT' || row.status == 'VIEWED'"
|
||||
>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#/"
|
||||
@click.self="sendEstimate(row.id)"
|
||||
>
|
||||
<font-awesome-icon
|
||||
icon="paper-plane"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('estimates.resend_estimate') }}
|
||||
</a>
|
||||
</v-dropdown-item>
|
||||
<!-- -->
|
||||
<v-dropdown-item v-if="row.status !== 'ACCEPTED'">
|
||||
<a class="dropdown-item" href="#/" @click.self="onMarkAsAccepted(row.id)">
|
||||
<font-awesome-icon icon="check-circle" class="dropdown-item-icon" />
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#/"
|
||||
@click.self="onMarkAsAccepted(row.id)"
|
||||
>
|
||||
<font-awesome-icon
|
||||
icon="check-circle"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('estimates.mark_as_accepted') }}
|
||||
</a>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item v-if="row.status !== 'REJECTED'">
|
||||
<a class="dropdown-item" href="#/" @click.self="onMarkAsRejected(row.id)">
|
||||
<font-awesome-icon icon="times-circle" class="dropdown-item-icon" />
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#/"
|
||||
@click.self="onMarkAsRejected(row.id)"
|
||||
>
|
||||
<font-awesome-icon
|
||||
icon="times-circle"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('estimates.mark_as_rejected') }}
|
||||
</a>
|
||||
</v-dropdown-item>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div v-if="estimate" class="main-content estimate-view-page">
|
||||
<div class="page-header">
|
||||
<h3 class="page-title"> {{ estimate.estimate_number }}</h3>
|
||||
<h3 class="page-title">{{ estimate.estimate_number }}</h3>
|
||||
<div class="page-actions row">
|
||||
<div class="col-xs-2 mr-3">
|
||||
<base-button
|
||||
@ -26,19 +26,42 @@
|
||||
{{ $t('estimates.send_estimate') }}
|
||||
</base-button>
|
||||
</div>
|
||||
<v-dropdown :close-on-select="false" align="left" class="filter-container">
|
||||
<v-dropdown
|
||||
:close-on-select="true"
|
||||
align="left"
|
||||
class="filter-container"
|
||||
>
|
||||
<a slot="activator" href="#">
|
||||
<base-button color="theme">
|
||||
<font-awesome-icon icon="ellipsis-h" />
|
||||
</base-button>
|
||||
</a>
|
||||
<v-dropdown-item>
|
||||
<router-link :to="{path: `/admin/estimates/${$route.params.id}/edit`}" class="dropdown-item">
|
||||
<font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon"/>
|
||||
<div class="dropdown-item" @click="copyPdfUrl()">
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'link']"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('general.copy_pdf_url') }}
|
||||
</div>
|
||||
<router-link
|
||||
:to="{ path: `/admin/estimates/${$route.params.id}/edit` }"
|
||||
class="dropdown-item"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'pencil-alt']"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('general.edit') }}
|
||||
</router-link>
|
||||
<div class="dropdown-item" @click="removeEstimate($route.params.id)">
|
||||
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
|
||||
<div
|
||||
class="dropdown-item"
|
||||
@click="removeEstimate($route.params.id)"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'trash']"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('general.delete') }}
|
||||
</div>
|
||||
</v-dropdown-item>
|
||||
@ -57,14 +80,18 @@
|
||||
align-icon="right"
|
||||
@input="onSearched()"
|
||||
/>
|
||||
<div
|
||||
class="btn-group ml-3"
|
||||
role="group"
|
||||
aria-label="First group"
|
||||
>
|
||||
<v-dropdown :close-on-select="false" align="left" class="filter-container">
|
||||
<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">
|
||||
<base-button
|
||||
class="inv-button inv-filter-fields-btn"
|
||||
color="default"
|
||||
size="medium"
|
||||
>
|
||||
<font-awesome-icon icon="filter" />
|
||||
</base-button>
|
||||
</a>
|
||||
@ -80,8 +107,10 @@
|
||||
class="inv-radio"
|
||||
value="estimate_date"
|
||||
@change="onSearched"
|
||||
>
|
||||
<label class="inv-label" for="filter_estimate_date">{{ $t('reports.estimates.estimate_date') }}</label>
|
||||
/>
|
||||
<label class="inv-label" for="filter_estimate_date">{{
|
||||
$t('reports.estimates.estimate_date')
|
||||
}}</label>
|
||||
</div>
|
||||
<div class="filter-items">
|
||||
<input
|
||||
@ -92,8 +121,10 @@
|
||||
class="inv-radio"
|
||||
value="expiry_date"
|
||||
@change="onSearched"
|
||||
>
|
||||
<label class="inv-label" for="filter_due_date">{{ $t('estimates.due_date') }}</label>
|
||||
/>
|
||||
<label class="inv-label" for="filter_due_date">{{
|
||||
$t('estimates.due_date')
|
||||
}}</label>
|
||||
</div>
|
||||
<div class="filter-items">
|
||||
<input
|
||||
@ -104,11 +135,19 @@
|
||||
class="inv-radio"
|
||||
value="estimate_number"
|
||||
@change="onSearched"
|
||||
>
|
||||
<label class="inv-label" for="filter_estimate_number">{{ $t('estimates.estimate_number') }}</label>
|
||||
/>
|
||||
<label class="inv-label" for="filter_estimate_number">{{
|
||||
$t('estimates.estimate_number')
|
||||
}}</label>
|
||||
</div>
|
||||
</v-dropdown>
|
||||
<base-button v-tooltip.top-center="{ content: getOrderName }" class="inv-button inv-filter-sorting-btn" color="default" size="medium" @click="sortData">
|
||||
<base-button
|
||||
v-tooltip.top-center="{ content: getOrderName }"
|
||||
class="inv-button inv-filter-sorting-btn"
|
||||
color="default"
|
||||
size="medium"
|
||||
@click="sortData"
|
||||
>
|
||||
<font-awesome-icon v-if="getOrderBy" icon="sort-amount-up" />
|
||||
<font-awesome-icon v-else icon="sort-amount-down" />
|
||||
</base-button>
|
||||
@ -116,7 +155,7 @@
|
||||
</div>
|
||||
<div class="side-content">
|
||||
<router-link
|
||||
v-for="(estimate,index) in estimates"
|
||||
v-for="(estimate, index) in estimates"
|
||||
:to="`/admin/estimates/${estimate.id}/view`"
|
||||
:key="index"
|
||||
class="side-estimate"
|
||||
@ -124,10 +163,20 @@
|
||||
<div class="left">
|
||||
<div class="inv-name">{{ estimate.user.name }}</div>
|
||||
<div class="inv-number">{{ estimate.estimate_number }}</div>
|
||||
<div :class="'est-status-'+estimate.status.toLowerCase()" class="inv-status">{{ estimate.status }}</div>
|
||||
<div
|
||||
:class="'est-status-' + estimate.status.toLowerCase()"
|
||||
class="inv-status"
|
||||
>
|
||||
{{ estimate.status }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="inv-amount" v-html="$utils.formatMoney(estimate.total, estimate.user.currency)" />
|
||||
<div
|
||||
class="inv-amount"
|
||||
v-html="
|
||||
$utils.formatMoney(estimate.total, estimate.user.currency)
|
||||
"
|
||||
/>
|
||||
<div class="inv-date">{{ estimate.formattedEstimateDate }}</div>
|
||||
</div>
|
||||
</router-link>
|
||||
@ -137,7 +186,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="estimate-view-page-container">
|
||||
<iframe :src="`${shareableLink}`" class="frame-style"/>
|
||||
<iframe :src="`${shareableLink}`" class="frame-style" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -289,6 +338,13 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
copyPdfUrl () {
|
||||
let pdfUrl = `${window.location.origin}/estimates/pdf/${this.estimate.unique_hash}`
|
||||
|
||||
let response = this.$utils.copyTextToClipboard(pdfUrl)
|
||||
|
||||
window.toastr['success'](this.$tc('Copied PDF url to clipboard!'))
|
||||
},
|
||||
async removeEstimate (id) {
|
||||
window.swal({
|
||||
title: 'Deleted',
|
||||
|
||||
@ -1,19 +1,15 @@
|
||||
<template>
|
||||
<div class="invoice-index-page invoices main-content">
|
||||
<div class="page-header">
|
||||
<h3 class="page-title"> {{ $t('invoices.title') }}</h3>
|
||||
<h3 class="page-title">{{ $t('invoices.title') }}</h3>
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item">
|
||||
<router-link
|
||||
slot="item-title"
|
||||
to="dashboard">
|
||||
<router-link slot="item-title" to="dashboard">
|
||||
{{ $t('general.home') }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<router-link
|
||||
slot="item-title"
|
||||
to="#">
|
||||
<router-link slot="item-title" to="#">
|
||||
{{ $tc('invoices.invoice', 2) }}
|
||||
</router-link>
|
||||
</li>
|
||||
@ -32,7 +28,11 @@
|
||||
{{ $t('general.filter') }}
|
||||
</base-button>
|
||||
</div>
|
||||
<router-link slot="item-title" class="col-xs-2" to="/admin/invoices/create">
|
||||
<router-link
|
||||
slot="item-title"
|
||||
class="col-xs-2"
|
||||
to="/admin/invoices/create"
|
||||
>
|
||||
<base-button size="large" icon="plus" color="theme">
|
||||
{{ $t('invoices.new_invoice') }}
|
||||
</base-button>
|
||||
@ -44,7 +44,7 @@
|
||||
<div v-show="showFilters" class="filter-section">
|
||||
<div class="filter-container">
|
||||
<div class="filter-customer">
|
||||
<label>{{ $tc('customers.customer',1) }} </label>
|
||||
<label>{{ $tc('customers.customer', 1) }} </label>
|
||||
<base-customer-select
|
||||
ref="customerSelect"
|
||||
@select="onSelectCustomer"
|
||||
@ -88,22 +88,29 @@
|
||||
</div>
|
||||
<div class="filter-invoice">
|
||||
<label>{{ $t('invoices.invoice_number') }}</label>
|
||||
<base-input
|
||||
v-model="filters.invoice_number"
|
||||
icon="hashtag"/>
|
||||
<base-input v-model="filters.invoice_number" icon="hashtag" />
|
||||
</div>
|
||||
</div>
|
||||
<label class="clear-filter" @click="clearFilter">{{ $t('general.clear_all') }}</label>
|
||||
<label class="clear-filter" @click="clearFilter">{{
|
||||
$t('general.clear_all')
|
||||
}}</label>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<div v-cloak v-show="showEmptyScreen" class="col-xs-1 no-data-info" align="center">
|
||||
<moon-walker-icon class="mt-5 mb-4"/>
|
||||
<div
|
||||
v-cloak
|
||||
v-show="showEmptyScreen"
|
||||
class="col-xs-1 no-data-info"
|
||||
align="center"
|
||||
>
|
||||
<moon-walker-icon class="mt-5 mb-4" />
|
||||
<div class="row" align="center">
|
||||
<label class="col title">{{ $t('invoices.no_invoices') }}</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="description col mt-1" align="center">{{ $t('invoices.list_of_invoices') }}</label>
|
||||
<label class="description col mt-1" align="center">{{
|
||||
$t('invoices.list_of_invoices')
|
||||
}}</label>
|
||||
</div>
|
||||
<div class="btn-container">
|
||||
<base-button
|
||||
@ -120,28 +127,65 @@
|
||||
|
||||
<div v-show="!showEmptyScreen" class="table-container">
|
||||
<div class="table-actions mt-5">
|
||||
<p class="table-stats">{{ $t('general.showing') }}: <b>{{ invoices.length }}</b> {{ $t('general.of') }} <b>{{ totalInvoices }}</b></p>
|
||||
<p class="table-stats">
|
||||
{{ $t('general.showing') }}: <b>{{ invoices.length }}</b>
|
||||
{{ $t('general.of') }} <b>{{ totalInvoices }}</b>
|
||||
</p>
|
||||
|
||||
<!-- Tabs -->
|
||||
<ul class="tabs">
|
||||
<li class="tab" @click="getStatus('UNPAID')">
|
||||
<a :class="['tab-link', {'a-active': filters.status.value === 'UNPAID'}]" href="#" >{{ $t('general.due') }}</a>
|
||||
<a
|
||||
:class="[
|
||||
'tab-link',
|
||||
{ 'a-active': filters.status.value === 'UNPAID' },
|
||||
]"
|
||||
href="#"
|
||||
>{{ $t('general.due') }}</a
|
||||
>
|
||||
</li>
|
||||
<li class="tab" @click="getStatus('DRAFT')">
|
||||
<a :class="['tab-link', {'a-active': filters.status.value === 'DRAFT'}]" href="#">{{ $t('general.draft') }}</a>
|
||||
<a
|
||||
:class="[
|
||||
'tab-link',
|
||||
{ 'a-active': filters.status.value === 'DRAFT' },
|
||||
]"
|
||||
href="#"
|
||||
>{{ $t('general.draft') }}</a
|
||||
>
|
||||
</li>
|
||||
<li class="tab" @click="getStatus('')">
|
||||
<a :class="['tab-link', {'a-active': filters.status.value === '' || filters.status.value === null || filters.status.value !== 'DRAFT' && filters.status.value !== 'UNPAID'}]" href="#">{{ $t('general.all') }}</a>
|
||||
<a
|
||||
:class="[
|
||||
'tab-link',
|
||||
{
|
||||
'a-active':
|
||||
filters.status.value === '' ||
|
||||
filters.status.value === null ||
|
||||
(filters.status.value !== 'DRAFT' &&
|
||||
filters.status.value !== 'UNPAID'),
|
||||
},
|
||||
]"
|
||||
href="#"
|
||||
>{{ $t('general.all') }}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<transition name="fade">
|
||||
<v-dropdown v-if="selectedInvoices.length" :show-arrow="false">
|
||||
<span slot="activator" href="#" class="table-actions-button dropdown-toggle">
|
||||
<span
|
||||
slot="activator"
|
||||
href="#"
|
||||
class="table-actions-button dropdown-toggle"
|
||||
>
|
||||
{{ $t('general.actions') }}
|
||||
</span>
|
||||
<v-dropdown-item>
|
||||
<div class="dropdown-item" @click="removeMultipleInvoices">
|
||||
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'trash']"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('general.delete') }}
|
||||
</div>
|
||||
</v-dropdown-item>
|
||||
@ -155,8 +199,12 @@
|
||||
type="checkbox"
|
||||
class="custom-control-input"
|
||||
@change="selectAllInvoices"
|
||||
/>
|
||||
<label
|
||||
v-show="!isRequestOngoing"
|
||||
for="select-all"
|
||||
class="custom-control-label selectall"
|
||||
>
|
||||
<label v-show="!isRequestOngoing" for="select-all" class="custom-control-label selectall">
|
||||
<span class="select-all-label">{{ $t('general.select_all') }} </span>
|
||||
</label>
|
||||
</div>
|
||||
@ -180,8 +228,8 @@
|
||||
:value="row.id"
|
||||
type="checkbox"
|
||||
class="custom-control-input"
|
||||
>
|
||||
<label :for="row.id" class="custom-control-label"/>
|
||||
/>
|
||||
<label :for="row.id" class="custom-control-label" />
|
||||
</div>
|
||||
</template>
|
||||
</table-column>
|
||||
@ -195,35 +243,33 @@
|
||||
width="20%"
|
||||
show="name"
|
||||
/>
|
||||
<table-column
|
||||
:label="$t('invoices.status')"
|
||||
sort-as="status"
|
||||
>
|
||||
<template slot-scope="row" >
|
||||
<table-column :label="$t('invoices.status')" sort-as="status">
|
||||
<template slot-scope="row">
|
||||
<span> {{ $t('invoices.status') }}</span>
|
||||
<span :class="'inv-status-'+row.status.toLowerCase()">{{ (row.status != 'PARTIALLY_PAID')? row.status : row.status.replace('_', ' ') }}</span>
|
||||
<span :class="'inv-status-' + row.status.toLowerCase()">{{
|
||||
row.status != 'PARTIALLY_PAID'
|
||||
? row.status
|
||||
: row.status.replace('_', ' ')
|
||||
}}</span>
|
||||
</template>
|
||||
</table-column>
|
||||
<table-column
|
||||
:label="$t('invoices.paid_status')"
|
||||
sort-as="paid_status"
|
||||
>
|
||||
<table-column :label="$t('invoices.paid_status')" sort-as="paid_status">
|
||||
<template slot-scope="row">
|
||||
<span>{{ $t('invoices.paid_status') }}</span>
|
||||
<span :class="'inv-status-'+row.paid_status.toLowerCase()">{{ (row.paid_status != 'PARTIALLY_PAID')? row.paid_status : row.paid_status.replace('_', ' ') }}</span>
|
||||
<span :class="'inv-status-' + row.paid_status.toLowerCase()">{{
|
||||
row.paid_status != 'PARTIALLY_PAID'
|
||||
? row.paid_status
|
||||
: row.paid_status.replace('_', ' ')
|
||||
}}</span>
|
||||
</template>
|
||||
</table-column>
|
||||
<table-column
|
||||
:label="$t('invoices.number')"
|
||||
show="invoice_number"
|
||||
/>
|
||||
<table-column
|
||||
:label="$t('invoices.amount_due')"
|
||||
sort-as="due_amount"
|
||||
>
|
||||
<table-column :label="$t('invoices.number')" show="invoice_number" />
|
||||
<table-column :label="$t('invoices.amount_due')" sort-as="due_amount">
|
||||
<template slot-scope="row">
|
||||
<span>{{ $t('invoices.amount_due') }}</span>
|
||||
<div v-html="$utils.formatMoney(row.due_amount, row.user.currency)"/>
|
||||
<div
|
||||
v-html="$utils.formatMoney(row.due_amount, row.user.currency)"
|
||||
/>
|
||||
</template>
|
||||
</table-column>
|
||||
<table-column
|
||||
@ -238,42 +284,91 @@
|
||||
<dot-icon />
|
||||
</a>
|
||||
<v-dropdown-item>
|
||||
<router-link :to="{path: `invoices/${row.id}/edit`}" class="dropdown-item">
|
||||
<font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon"/>
|
||||
<router-link
|
||||
:to="{ path: `invoices/${row.id}/edit` }"
|
||||
class="dropdown-item"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'pencil-alt']"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('general.edit') }}
|
||||
</router-link>
|
||||
<router-link :to="{path: `invoices/${row.id}/view`}" class="dropdown-item">
|
||||
<router-link
|
||||
:to="{ path: `invoices/${row.id}/view` }"
|
||||
class="dropdown-item"
|
||||
>
|
||||
<font-awesome-icon icon="eye" class="dropdown-item-icon" />
|
||||
{{ $t('invoices.view') }}
|
||||
</router-link>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item v-if="row.status == 'DRAFT'">
|
||||
<a class="dropdown-item" href="#/" @click="sendInvoice(row.id)" >
|
||||
<font-awesome-icon icon="paper-plane" class="dropdown-item-icon" />
|
||||
<a class="dropdown-item" href="#/" @click="sendInvoice(row.id)">
|
||||
<font-awesome-icon
|
||||
icon="paper-plane"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('invoices.send_invoice') }}
|
||||
</a>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item
|
||||
v-if="row.status === 'SENT' || row.status === 'VIEWED'"
|
||||
>
|
||||
<a class="dropdown-item" href="#/" @click="sendInvoice(row.id)">
|
||||
<font-awesome-icon
|
||||
icon="paper-plane"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('invoices.resend_invoice') }}
|
||||
</a>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item v-if="row.status == 'DRAFT'">
|
||||
<a class="dropdown-item" href="#/" @click="markInvoiceAsSent(row.id)">
|
||||
<font-awesome-icon icon="check-circle" class="dropdown-item-icon" />
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#/"
|
||||
@click="markInvoiceAsSent(row.id)"
|
||||
>
|
||||
<font-awesome-icon
|
||||
icon="check-circle"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('invoices.mark_as_sent') }}
|
||||
</a>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item v-if="row.status === 'SENT' || row.status === 'VIEWED' || row.status === 'OVERDUE'">
|
||||
<router-link :to="`/admin/payments/${row.id}/create`" class="dropdown-item">
|
||||
<font-awesome-icon :icon="['fas', 'credit-card']" class="dropdown-item-icon"/>
|
||||
<v-dropdown-item
|
||||
v-if="
|
||||
row.status === 'SENT' ||
|
||||
row.status === 'VIEWED' ||
|
||||
row.status === 'OVERDUE'
|
||||
"
|
||||
>
|
||||
<router-link
|
||||
:to="`/admin/payments/${row.id}/create`"
|
||||
class="dropdown-item"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'credit-card']"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('payments.record_payment') }}
|
||||
</router-link>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item>
|
||||
<a class="dropdown-item" href="#/" @click="onCloneInvoice(row.id)">
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#/"
|
||||
@click="onCloneInvoice(row.id)"
|
||||
>
|
||||
<font-awesome-icon icon="copy" class="dropdown-item-icon" />
|
||||
{{ $t('invoices.clone_invoice') }}
|
||||
</a>
|
||||
</v-dropdown-item>
|
||||
<v-dropdown-item>
|
||||
<div class="dropdown-item" @click="removeInvoice(row.id)">
|
||||
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'trash']"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('general.delete') }}
|
||||
</div>
|
||||
</v-dropdown-item>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div v-if="invoice" class="main-content invoice-view-page">
|
||||
<div class="page-header">
|
||||
<h3 class="page-title"> {{ invoice.invoice_number }}</h3>
|
||||
<h3 class="page-title">{{ invoice.invoice_number }}</h3>
|
||||
<div class="page-actions row">
|
||||
<div class="col-xs-2 mr-3">
|
||||
<base-button
|
||||
@ -24,26 +24,47 @@
|
||||
>
|
||||
{{ $t('invoices.send_invoice') }}
|
||||
</base-button>
|
||||
<router-link v-if="invoice.status === 'SENT'" :to="`/admin/payments/${$route.params.id}/create`">
|
||||
<base-button
|
||||
color="theme"
|
||||
>
|
||||
<router-link
|
||||
v-if="invoice.status === 'SENT'"
|
||||
:to="`/admin/payments/${$route.params.id}/create`"
|
||||
>
|
||||
<base-button color="theme">
|
||||
{{ $t('payments.record_payment') }}
|
||||
</base-button>
|
||||
</router-link>
|
||||
<v-dropdown :close-on-select="false" align="left" class="filter-container">
|
||||
<v-dropdown
|
||||
:close-on-select="true"
|
||||
align="left"
|
||||
class="filter-container"
|
||||
>
|
||||
<a slot="activator" href="#">
|
||||
<base-button color="theme">
|
||||
<font-awesome-icon icon="ellipsis-h" />
|
||||
</base-button>
|
||||
</a>
|
||||
<v-dropdown-item>
|
||||
<router-link :to="{path: `/admin/invoices/${$route.params.id}/edit`}" class="dropdown-item">
|
||||
<font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon"/>
|
||||
<div class="dropdown-item" @click="copyPdfUrl">
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'link']"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('general.copy_pdf_url') }}
|
||||
</div>
|
||||
<router-link
|
||||
:to="{ path: `/admin/invoices/${$route.params.id}/edit` }"
|
||||
class="dropdown-item"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'pencil-alt']"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('general.edit') }}
|
||||
</router-link>
|
||||
<div class="dropdown-item" @click="removeInvoice($route.params.id)">
|
||||
<font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" />
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'trash']"
|
||||
class="dropdown-item-icon"
|
||||
/>
|
||||
{{ $t('general.delete') }}
|
||||
</div>
|
||||
</v-dropdown-item>
|
||||
@ -61,14 +82,18 @@
|
||||
align-icon="right"
|
||||
@input="onSearch"
|
||||
/>
|
||||
<div
|
||||
class="btn-group ml-3"
|
||||
role="group"
|
||||
aria-label="First group"
|
||||
>
|
||||
<v-dropdown :close-on-select="false" align="left" class="filter-container">
|
||||
<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">
|
||||
<base-button
|
||||
class="inv-button inv-filter-fields-btn"
|
||||
color="default"
|
||||
size="medium"
|
||||
>
|
||||
<font-awesome-icon icon="filter" />
|
||||
</base-button>
|
||||
</a>
|
||||
@ -84,8 +109,10 @@
|
||||
class="inv-radio"
|
||||
value="invoice_date"
|
||||
@change="onSearch"
|
||||
>
|
||||
<label class="inv-label" for="filter_invoice_date">{{ $t('invoices.invoice_date') }}</label>
|
||||
/>
|
||||
<label class="inv-label" for="filter_invoice_date">{{
|
||||
$t('invoices.invoice_date')
|
||||
}}</label>
|
||||
</div>
|
||||
<div class="filter-items">
|
||||
<input
|
||||
@ -96,8 +123,10 @@
|
||||
class="inv-radio"
|
||||
value="due_date"
|
||||
@change="onSearch"
|
||||
>
|
||||
<label class="inv-label" for="filter_due_date">{{ $t('invoices.due_date') }}</label>
|
||||
/>
|
||||
<label class="inv-label" for="filter_due_date">{{
|
||||
$t('invoices.due_date')
|
||||
}}</label>
|
||||
</div>
|
||||
<div class="filter-items">
|
||||
<input
|
||||
@ -108,11 +137,19 @@
|
||||
class="inv-radio"
|
||||
value="invoice_number"
|
||||
@change="onSearch"
|
||||
>
|
||||
<label class="inv-label" for="filter_invoice_number">{{ $t('invoices.invoice_number') }}</label>
|
||||
/>
|
||||
<label class="inv-label" for="filter_invoice_number">{{
|
||||
$t('invoices.invoice_number')
|
||||
}}</label>
|
||||
</div>
|
||||
</v-dropdown>
|
||||
<base-button v-tooltip.top-center="{ content: getOrderName }" class="inv-button inv-filter-sorting-btn" color="default" size="medium" @click="sortData">
|
||||
<base-button
|
||||
v-tooltip.top-center="{ content: getOrderName }"
|
||||
class="inv-button inv-filter-sorting-btn"
|
||||
color="default"
|
||||
size="medium"
|
||||
@click="sortData"
|
||||
>
|
||||
<font-awesome-icon v-if="getOrderBy" icon="sort-amount-up" />
|
||||
<font-awesome-icon v-else icon="sort-amount-down" />
|
||||
</base-button>
|
||||
@ -121,7 +158,7 @@
|
||||
<base-loader v-if="isSearching" />
|
||||
<div v-else class="side-content">
|
||||
<router-link
|
||||
v-for="(invoice,index) in invoices"
|
||||
v-for="(invoice, index) in invoices"
|
||||
:to="`/admin/invoices/${invoice.id}/view`"
|
||||
:key="index"
|
||||
class="side-invoice"
|
||||
@ -129,10 +166,20 @@
|
||||
<div class="left">
|
||||
<div class="inv-name">{{ invoice.user.name }}</div>
|
||||
<div class="inv-number">{{ invoice.invoice_number }}</div>
|
||||
<div :class="'inv-status-'+invoice.status.toLowerCase()" class="inv-status">{{ invoice.status }}</div>
|
||||
<div
|
||||
:class="'inv-status-' + invoice.status.toLowerCase()"
|
||||
class="inv-status"
|
||||
>
|
||||
{{ invoice.status }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="inv-amount" v-html="$utils.formatMoney(invoice.due_amount, invoice.user.currency)" />
|
||||
<div
|
||||
class="inv-amount"
|
||||
v-html="
|
||||
$utils.formatMoney(invoice.due_amount, invoice.user.currency)
|
||||
"
|
||||
/>
|
||||
<div class="inv-date">{{ invoice.formattedInvoiceDate }}</div>
|
||||
</div>
|
||||
</router-link>
|
||||
@ -141,8 +188,8 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="invoice-view-page-container" >
|
||||
<iframe :src="`${shareableLink}`" class="frame-style"/>
|
||||
<div class="invoice-view-page-container">
|
||||
<iframe :src="`${shareableLink}`" class="frame-style" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -291,6 +338,14 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
copyPdfUrl () {
|
||||
let pdfUrl = `${window.location.origin}/invoices/pdf/${this.invoice.unique_hash}`
|
||||
|
||||
let response = this.$utils.copyTextToClipboard(pdfUrl)
|
||||
|
||||
window.toastr['success'](this.$tc('Copied PDF url to clipboard!'))
|
||||
|
||||
},
|
||||
async removeInvoice (id) {
|
||||
this.selectInvoice([parseInt(id)])
|
||||
this.id = id
|
||||
|
||||
@ -54,7 +54,8 @@ import {
|
||||
faEyeSlash,
|
||||
faSyncAlt,
|
||||
faRocket,
|
||||
faCamera
|
||||
faCamera,
|
||||
faLink,
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { far } from '@fortawesome/free-regular-svg-icons'
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||
@ -119,7 +120,8 @@ library.add(
|
||||
faPaperPlane,
|
||||
faSyncAlt,
|
||||
faRocket,
|
||||
faCamera
|
||||
faCamera,
|
||||
faLink
|
||||
)
|
||||
|
||||
Vue.component('font-awesome-icon', FontAwesomeIcon)
|
||||
|
||||
Reference in New Issue
Block a user