mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-28 12:11:08 -04:00
Compare commits
75 Commits
tax-calcul
...
dark-actio
| Author | SHA1 | Date | |
|---|---|---|---|
| 150380791f | |||
| 45aaee72d8 | |||
| f4bc78ce98 | |||
| ba769864d4 | |||
| de235a91e5 | |||
| 18dc88682c | |||
| deb039ba02 | |||
| 7e80bfb507 | |||
| 8a5632c7d6 | |||
| 1a4309ca69 | |||
| 3b3da13218 | |||
| 5440b0f354 | |||
| 9249105ad6 | |||
| 238cdb3c25 | |||
| 55bf70c868 | |||
| 0c5adff9b4 | |||
| 3d5732ee26 | |||
| 5aa7decdbe | |||
| 5c67780870 | |||
| ba7f619c67 | |||
| 82efad71c0 | |||
| 826ef72faa | |||
| 2adaa7a84a | |||
| 13557ea075 | |||
| ce88c772d1 | |||
| a32d36363d | |||
| f874b3507d | |||
| c36d25931f | |||
| 1e6c3b287f | |||
| 0462ff60a0 | |||
| 29a135adaf | |||
| 1aceb2c672 | |||
| fb9fab641d | |||
| 8f2edc220b | |||
| d14ab013ad | |||
| f6639f5863 | |||
| c5acf1343e | |||
| 0321ca5515 | |||
| bd345949e5 | |||
| b4b00ebdd6 | |||
| 43316dae28 | |||
| 80e2548b38 | |||
| e8d92cd641 | |||
| 2c8bb38531 | |||
| 04c7ae39a2 | |||
| af2482a69c | |||
| cac35826c2 | |||
| 18b5705372 | |||
| c61fbad5ce | |||
| 15f3f566e3 | |||
| 2e93082282 | |||
| ca55221c4f | |||
| 98196194e2 | |||
| df04fd9e53 | |||
| 189c51cdf4 | |||
| bd5f0fe5cf | |||
| 787619b907 | |||
| fd70ab9a99 | |||
| 33315638df | |||
| bba14bf51a | |||
| ea41989034 | |||
| 3f3f83a00a | |||
| adc5962071 | |||
| c4c00002d7 | |||
| a7c1e12db6 | |||
| 32949d1eec | |||
| 7718f77f3d | |||
| a9e54981bf | |||
| ef35293f8a | |||
| 5c63770b6b | |||
| d130e20c92 | |||
| 586fb1ae10 | |||
| 20c2502e31 | |||
| 0e31f85c18 | |||
| e7301eb7a3 |
9
.github/workflows/uffizzi-build.yml
vendored
9
.github/workflows/uffizzi-build.yml
vendored
@ -14,6 +14,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout git repo
|
- name: Checkout git repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
- name: Generate UUID image name
|
- name: Generate UUID image name
|
||||||
id: uuid
|
id: uuid
|
||||||
run: echo "UUID_TAG_APP=$(uuidgen)" >> $GITHUB_ENV
|
run: echo "UUID_TAG_APP=$(uuidgen)" >> $GITHUB_ENV
|
||||||
@ -31,10 +33,11 @@ jobs:
|
|||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
file: ./uffizzi/Dockerfile
|
file: ./uffizzi/Dockerfile
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
|
||||||
build-nginx:
|
build-nginx:
|
||||||
needs:
|
|
||||||
- build-application
|
|
||||||
name: Build and Push `nginx`
|
name: Build and Push `nginx`
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }}
|
if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }}
|
||||||
@ -62,8 +65,6 @@ jobs:
|
|||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
file: ./uffizzi/nginx/Dockerfile
|
file: ./uffizzi/nginx/Dockerfile
|
||||||
build-args: |
|
|
||||||
BASE_IMAGE=${{ needs.build-application.outputs.tags }}
|
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,4 +17,3 @@ Homestead.yaml
|
|||||||
/public/docs
|
/public/docs
|
||||||
/.scribe
|
/.scribe
|
||||||
!storage/fonts/.gitkeep
|
!storage/fonts/.gitkeep
|
||||||
.DS_Store
|
|
||||||
|
|||||||
@ -55,7 +55,7 @@ class CreateTemplateCommand extends Command
|
|||||||
copy(public_path("/build/img/PDF/{$type}1.png"), public_path("/build/img/PDF/{$templateName}.png"));
|
copy(public_path("/build/img/PDF/{$type}1.png"), public_path("/build/img/PDF/{$templateName}.png"));
|
||||||
copy(resource_path("/static/img/PDF/{$type}1.png"), resource_path("/static/img/PDF/{$templateName}.png"));
|
copy(resource_path("/static/img/PDF/{$type}1.png"), resource_path("/static/img/PDF/{$templateName}.png"));
|
||||||
|
|
||||||
$path = resource_path("views/app/pdf/{$type}/{$templateName}.blade.php");
|
$path = resource_path("app/pdf/{$type}/{$templateName}.blade.php");
|
||||||
$type = ucfirst($type);
|
$type = ucfirst($type);
|
||||||
$this->info("{$type} Template created successfully at ".$path);
|
$this->info("{$type} Template created successfully at ".$path);
|
||||||
|
|
||||||
|
|||||||
@ -103,6 +103,7 @@ class CustomerStatsController extends Controller
|
|||||||
)
|
)
|
||||||
->whereCompany()
|
->whereCompany()
|
||||||
->whereCustomer($customer->id)
|
->whereCustomer($customer->id)
|
||||||
|
->where('status', '<>', Invoice::STATUS_DRAFT)
|
||||||
->sum('total');
|
->sum('total');
|
||||||
$totalReceipts = Payment::whereBetween(
|
$totalReceipts = Payment::whereBetween(
|
||||||
'payment_date',
|
'payment_date',
|
||||||
|
|||||||
@ -104,6 +104,7 @@ class DashboardController extends Controller
|
|||||||
'invoice_date',
|
'invoice_date',
|
||||||
[$startDate->format('Y-m-d'), $start->format('Y-m-d')]
|
[$startDate->format('Y-m-d'), $start->format('Y-m-d')]
|
||||||
)
|
)
|
||||||
|
->where('status', '<>', Invoice::STATUS_DRAFT)
|
||||||
->whereCompany()
|
->whereCompany()
|
||||||
->sum('base_total');
|
->sum('base_total');
|
||||||
|
|
||||||
@ -141,6 +142,7 @@ class DashboardController extends Controller
|
|||||||
$recent_due_invoices = Invoice::with('customer')
|
$recent_due_invoices = Invoice::with('customer')
|
||||||
->whereCompany()
|
->whereCompany()
|
||||||
->where('base_due_amount', '>', 0)
|
->where('base_due_amount', '>', 0)
|
||||||
|
->where('status', '<>', Invoice::STATUS_DRAFT)
|
||||||
->take(5)
|
->take(5)
|
||||||
->latest()
|
->latest()
|
||||||
->get();
|
->get();
|
||||||
|
|||||||
@ -24,6 +24,7 @@ class InvoicesController extends Controller
|
|||||||
$limit = $request->has('limit') ? $request->limit : 10;
|
$limit = $request->has('limit') ? $request->limit : 10;
|
||||||
|
|
||||||
$invoices = Invoice::whereCompany()
|
$invoices = Invoice::whereCompany()
|
||||||
|
->whereTabFilters($request->tab_status)
|
||||||
->join('customers', 'customers.id', '=', 'invoices.customer_id')
|
->join('customers', 'customers.id', '=', 'invoices.customer_id')
|
||||||
->applyFilters($request->all())
|
->applyFilters($request->all())
|
||||||
->select('invoices.*', 'customers.name')
|
->select('invoices.*', 'customers.name')
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
namespace Crater\Http\Requests;
|
namespace Crater\Http\Requests;
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class CompaniesRequest extends FormRequest
|
class CompaniesRequest extends FormRequest
|
||||||
@ -34,6 +33,10 @@ class CompaniesRequest extends FormRequest
|
|||||||
'currency' => [
|
'currency' => [
|
||||||
'required'
|
'required'
|
||||||
],
|
],
|
||||||
|
'slug' => [
|
||||||
|
'required',
|
||||||
|
Rule::unique('companies')
|
||||||
|
],
|
||||||
'address.name' => [
|
'address.name' => [
|
||||||
'nullable',
|
'nullable',
|
||||||
],
|
],
|
||||||
@ -68,11 +71,11 @@ class CompaniesRequest extends FormRequest
|
|||||||
{
|
{
|
||||||
return collect($this->validated())
|
return collect($this->validated())
|
||||||
->only([
|
->only([
|
||||||
'name'
|
'name',
|
||||||
|
'slug'
|
||||||
])
|
])
|
||||||
->merge([
|
->merge([
|
||||||
'owner_id' => $this->user()->id,
|
'owner_id' => $this->user()->id
|
||||||
'slug' => Str::slug($this->name)
|
|
||||||
])
|
])
|
||||||
->toArray();
|
->toArray();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,8 @@ class CompanyRequest extends FormRequest
|
|||||||
Rule::unique('companies')->ignore($this->header('company'), 'id'),
|
Rule::unique('companies')->ignore($this->header('company'), 'id'),
|
||||||
],
|
],
|
||||||
'slug' => [
|
'slug' => [
|
||||||
'nullable'
|
'required',
|
||||||
|
Rule::unique('companies')->ignore($this->header('company'), 'id'),
|
||||||
],
|
],
|
||||||
'address.country_id' => [
|
'address.country_id' => [
|
||||||
'required',
|
'required',
|
||||||
|
|||||||
@ -45,21 +45,15 @@ class EstimatesRequest extends FormRequest
|
|||||||
'nullable'
|
'nullable'
|
||||||
],
|
],
|
||||||
'discount' => [
|
'discount' => [
|
||||||
'numeric',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'discount_val' => [
|
'discount_val' => [
|
||||||
'integer',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'sub_total' => [
|
'sub_total' => [
|
||||||
'integer',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'total' => [
|
'total' => [
|
||||||
'integer',
|
|
||||||
'numeric',
|
|
||||||
'max:99999999',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'tax' => [
|
'tax' => [
|
||||||
@ -83,11 +77,9 @@ class EstimatesRequest extends FormRequest
|
|||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'items.*.quantity' => [
|
'items.*.quantity' => [
|
||||||
'integer',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'items.*.price' => [
|
'items.*.price' => [
|
||||||
'integer',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@ -45,21 +45,15 @@ class InvoicesRequest extends FormRequest
|
|||||||
'nullable'
|
'nullable'
|
||||||
],
|
],
|
||||||
'discount' => [
|
'discount' => [
|
||||||
'numeric',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'discount_val' => [
|
'discount_val' => [
|
||||||
'integer',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'sub_total' => [
|
'sub_total' => [
|
||||||
'integer',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'total' => [
|
'total' => [
|
||||||
'integer',
|
|
||||||
'numeric',
|
|
||||||
'max:99999999',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'tax' => [
|
'tax' => [
|
||||||
@ -83,11 +77,9 @@ class InvoicesRequest extends FormRequest
|
|||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'items.*.quantity' => [
|
'items.*.quantity' => [
|
||||||
'integer',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'items.*.price' => [
|
'items.*.price' => [
|
||||||
'integer',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@ -43,21 +43,15 @@ class RecurringInvoiceRequest extends FormRequest
|
|||||||
'nullable'
|
'nullable'
|
||||||
],
|
],
|
||||||
'discount' => [
|
'discount' => [
|
||||||
'numeric',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'discount_val' => [
|
'discount_val' => [
|
||||||
'integer',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'sub_total' => [
|
'sub_total' => [
|
||||||
'integer',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'total' => [
|
'total' => [
|
||||||
'integer',
|
|
||||||
'numeric',
|
|
||||||
'max:99999999',
|
|
||||||
'required',
|
'required',
|
||||||
],
|
],
|
||||||
'tax' => [
|
'tax' => [
|
||||||
|
|||||||
@ -23,7 +23,7 @@ class EstimateResource extends JsonResource
|
|||||||
'reference_number' => $this->reference_number,
|
'reference_number' => $this->reference_number,
|
||||||
'tax_per_item' => $this->tax_per_item,
|
'tax_per_item' => $this->tax_per_item,
|
||||||
'discount_per_item' => $this->discount_per_item,
|
'discount_per_item' => $this->discount_per_item,
|
||||||
'notes' => $this->getNotes(),
|
'notes' => $this->notes,
|
||||||
'discount' => $this->discount,
|
'discount' => $this->discount,
|
||||||
'discount_type' => $this->discount_type,
|
'discount_type' => $this->discount_type,
|
||||||
'discount_val' => $this->discount_val,
|
'discount_val' => $this->discount_val,
|
||||||
|
|||||||
@ -18,7 +18,7 @@ class PaymentResource extends JsonResource
|
|||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
'payment_number' => $this->payment_number,
|
'payment_number' => $this->payment_number,
|
||||||
'payment_date' => $this->payment_date,
|
'payment_date' => $this->payment_date,
|
||||||
'notes' => $this->getNotes(),
|
'notes' => $this->notes,
|
||||||
'amount' => $this->amount,
|
'amount' => $this->amount,
|
||||||
'unique_hash' => $this->unique_hash,
|
'unique_hash' => $this->unique_hash,
|
||||||
'invoice_id' => $this->invoice_id,
|
'invoice_id' => $this->invoice_id,
|
||||||
|
|||||||
@ -217,7 +217,7 @@ class Company extends Model implements HasMedia
|
|||||||
'estimate_billing_address_format' => $billingAddressFormat,
|
'estimate_billing_address_format' => $billingAddressFormat,
|
||||||
'payment_company_address_format' => $companyAddressFormat,
|
'payment_company_address_format' => $companyAddressFormat,
|
||||||
'payment_from_customer_address_format' => $paymentFromCustomerAddress,
|
'payment_from_customer_address_format' => $paymentFromCustomerAddress,
|
||||||
'currency' => request()->currency ?? 13,
|
'currency' => request()->currency ?? 1,
|
||||||
'time_zone' => 'Asia/Kolkata',
|
'time_zone' => 'Asia/Kolkata',
|
||||||
'language' => 'en',
|
'language' => 'en',
|
||||||
'fiscal_year' => '1-12',
|
'fiscal_year' => '1-12',
|
||||||
|
|||||||
@ -483,7 +483,8 @@ class Estimate extends Model implements HasMedia
|
|||||||
'{ESTIMATE_DATE}' => $this->formattedEstimateDate,
|
'{ESTIMATE_DATE}' => $this->formattedEstimateDate,
|
||||||
'{ESTIMATE_EXPIRY_DATE}' => $this->formattedExpiryDate,
|
'{ESTIMATE_EXPIRY_DATE}' => $this->formattedExpiryDate,
|
||||||
'{ESTIMATE_NUMBER}' => $this->estimate_number,
|
'{ESTIMATE_NUMBER}' => $this->estimate_number,
|
||||||
'{ESTIMATE_REF_NUMBER}' => $this->reference_number,
|
'{PDF_LINK}' => $this->estimatePdfUrl,
|
||||||
|
'{TOTAL_AMOUNT}' => format_money_pdf($this->total, $this->customer->currency)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -240,7 +240,7 @@ class Expense extends Model implements HasMedia
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($request->hasFile('attachment_receipt')) {
|
if ($request->hasFile('attachment_receipt')) {
|
||||||
$expense->addMediaFromRequest('attachment_receipt')->toMediaCollection('receipts');
|
$expense->addMediaFromRequest('attachment_receipt')->toMediaCollection('receipts', 'local');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->customFields) {
|
if ($request->customFields) {
|
||||||
@ -262,12 +262,12 @@ class Expense extends Model implements HasMedia
|
|||||||
ExchangeRateLog::addExchangeRateLog($this);
|
ExchangeRateLog::addExchangeRateLog($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($request->is_attachment_receipt_removed) && (bool) $request->is_attachment_receipt_removed) {
|
if (isset($request->is_attachment_receipt_removed) && $request->is_attachment_receipt_removed == "true") {
|
||||||
$this->clearMediaCollection('receipts');
|
$this->clearMediaCollection('receipts');
|
||||||
}
|
}
|
||||||
if ($request->hasFile('attachment_receipt')) {
|
if ($request->hasFile('attachment_receipt')) {
|
||||||
$this->clearMediaCollection('receipts');
|
$this->clearMediaCollection('receipts');
|
||||||
$this->addMediaFromRequest('attachment_receipt')->toMediaCollection('receipts');
|
$this->addMediaFromRequest('attachment_receipt')->toMediaCollection('receipts', 'local');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->customFields) {
|
if ($request->customFields) {
|
||||||
|
|||||||
@ -187,16 +187,6 @@ class Invoice extends Model implements HasMedia
|
|||||||
return Carbon::parse($this->invoice_date)->format($dateFormat);
|
return Carbon::parse($this->invoice_date)->format($dateFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scopeWhereStatus($query, $status)
|
|
||||||
{
|
|
||||||
return $query->where('invoices.status', $status);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function scopeWherePaidStatus($query, $status)
|
|
||||||
{
|
|
||||||
return $query->where('invoices.paid_status', $status);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function scopeWhereDueStatus($query, $status)
|
public function scopeWhereDueStatus($query, $status)
|
||||||
{
|
{
|
||||||
return $query->whereIn('invoices.paid_status', [
|
return $query->whereIn('invoices.paid_status', [
|
||||||
@ -234,6 +224,40 @@ class Invoice extends Model implements HasMedia
|
|||||||
$query->orderBy($orderByField, $orderBy);
|
$query->orderBy($orderByField, $orderBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function scopeWhereStatus($query, $status)
|
||||||
|
{
|
||||||
|
return $query->where('invoices.status', $status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeWherePaidStatus($query, $status)
|
||||||
|
{
|
||||||
|
return $query->where('invoices.paid_status', $status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeWhereTabFilters($query, $status)
|
||||||
|
{
|
||||||
|
if ($status == "DRAFT") {
|
||||||
|
return $query->where('invoices.status', $status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($status == "SENT") {
|
||||||
|
return $query->whereIn('invoices.status', [
|
||||||
|
self::STATUS_SENT,
|
||||||
|
self::STATUS_VIEWED,
|
||||||
|
self::STATUS_COMPLETED
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($status == 'DUE') {
|
||||||
|
return $query->whereIn('invoices.paid_status', [
|
||||||
|
self::STATUS_UNPAID,
|
||||||
|
self::STATUS_PARTIALLY_PAID,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
public function scopeApplyFilters($query, array $filters)
|
public function scopeApplyFilters($query, array $filters)
|
||||||
{
|
{
|
||||||
$filters = collect($filters);
|
$filters = collect($filters);
|
||||||
@ -249,17 +273,11 @@ class Invoice extends Model implements HasMedia
|
|||||||
$filters->get('status') == self::STATUS_PAID
|
$filters->get('status') == self::STATUS_PAID
|
||||||
) {
|
) {
|
||||||
$query->wherePaidStatus($filters->get('status'));
|
$query->wherePaidStatus($filters->get('status'));
|
||||||
} elseif ($filters->get('status') == 'DUE') {
|
|
||||||
$query->whereDueStatus($filters->get('status'));
|
|
||||||
} else {
|
} else {
|
||||||
$query->whereStatus($filters->get('status'));
|
$query->whereStatus($filters->get('status'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($filters->get('paid_status')) {
|
|
||||||
$query->wherePaidStatus($filters->get('status'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($filters->get('invoice_id')) {
|
if ($filters->get('invoice_id')) {
|
||||||
$query->whereInvoice($filters->get('invoice_id'));
|
$query->whereInvoice($filters->get('invoice_id'));
|
||||||
}
|
}
|
||||||
@ -651,7 +669,9 @@ class Invoice extends Model implements HasMedia
|
|||||||
'{INVOICE_DATE}' => $this->formattedInvoiceDate,
|
'{INVOICE_DATE}' => $this->formattedInvoiceDate,
|
||||||
'{INVOICE_DUE_DATE}' => $this->formattedDueDate,
|
'{INVOICE_DUE_DATE}' => $this->formattedDueDate,
|
||||||
'{INVOICE_NUMBER}' => $this->invoice_number,
|
'{INVOICE_NUMBER}' => $this->invoice_number,
|
||||||
'{INVOICE_REF_NUMBER}' => $this->reference_number,
|
'{PDF_LINK}' => $this->invoicePdfUrl,
|
||||||
|
'{DUE_AMOUNT}' => format_money_pdf($this->due_amount, $this->customer->currency),
|
||||||
|
'{TOTAL_AMOUNT}' => format_money_pdf($this->total, $this->customer->currency)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -435,7 +435,8 @@ class Payment extends Model implements HasMedia
|
|||||||
'{PAYMENT_DATE}' => $this->formattedPaymentDate,
|
'{PAYMENT_DATE}' => $this->formattedPaymentDate,
|
||||||
'{PAYMENT_MODE}' => $this->paymentMethod ? $this->paymentMethod->name : null,
|
'{PAYMENT_MODE}' => $this->paymentMethod ? $this->paymentMethod->name : null,
|
||||||
'{PAYMENT_NUMBER}' => $this->payment_number,
|
'{PAYMENT_NUMBER}' => $this->payment_number,
|
||||||
'{PAYMENT_AMOUNT}' => $this->reference_number,
|
'{PDF_LINK}' => $this->paymentPdfUrl,
|
||||||
|
'{PAYMENT_AMOUNT}' => format_money_pdf($this->amount, $this->customer->currency)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,6 @@ return [
|
|||||||
'tokenizer',
|
'tokenizer',
|
||||||
'JSON',
|
'JSON',
|
||||||
'cURL',
|
'cURL',
|
||||||
'zip',
|
|
||||||
],
|
],
|
||||||
'apache' => [
|
'apache' => [
|
||||||
'mod_rewrite',
|
'mod_rewrite',
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
"vite": "^2.6.1"
|
"vite": "^2.6.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@headlessui/vue": "^1.4.0",
|
"@headlessui/vue": "^1.5.0",
|
||||||
"@heroicons/vue": "^1.0.1",
|
"@heroicons/vue": "^1.0.1",
|
||||||
"@popperjs/core": "^2.9.2",
|
"@popperjs/core": "^2.9.2",
|
||||||
"@stripe/stripe-js": "^1.21.2",
|
"@stripe/stripe-js": "^1.21.2",
|
||||||
@ -48,7 +48,8 @@
|
|||||||
"mini-svg-data-uri": "^1.3.3",
|
"mini-svg-data-uri": "^1.3.3",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"pinia": "^2.0.4",
|
"pinia": "^2.0.4",
|
||||||
"v-money3": "^3.13.5",
|
"v-calendar": "3.0.0-alpha.8",
|
||||||
|
"v-money3": "3.16.1",
|
||||||
"v-tooltip": "^4.0.0-alpha.1",
|
"v-tooltip": "^4.0.0-alpha.1",
|
||||||
"vue": "^3.2.0-beta.5",
|
"vue": "^3.2.0-beta.5",
|
||||||
"vue-flatpickr-component": "^9.0.3",
|
"vue-flatpickr-component": "^9.0.3",
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
py-2
|
py-2
|
||||||
rounded-lg
|
rounded-lg
|
||||||
bg-opacity-40 bg-gray-300
|
bg-opacity-40 bg-gray-300
|
||||||
|
dark:bg-gray-700 dark:border-gray-600
|
||||||
whitespace-nowrap
|
whitespace-nowrap
|
||||||
flex-col
|
flex-col
|
||||||
mt-1
|
mt-1
|
||||||
@ -19,6 +20,7 @@
|
|||||||
text-sm
|
text-sm
|
||||||
font-medium
|
font-medium
|
||||||
text-black
|
text-black
|
||||||
|
dark:text-white
|
||||||
truncate
|
truncate
|
||||||
select-all select-color
|
select-all select-color
|
||||||
"
|
"
|
||||||
|
|||||||
@ -43,6 +43,12 @@
|
|||||||
max-w-full
|
max-w-full
|
||||||
left-0
|
left-0
|
||||||
top-3
|
top-3
|
||||||
|
bg-white
|
||||||
|
dark:border
|
||||||
|
dark:border-white/10
|
||||||
|
dark:text-white
|
||||||
|
dark:bg-gray-800
|
||||||
|
dark:shadow-glass
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -53,7 +59,7 @@
|
|||||||
ring-1 ring-black ring-opacity-5
|
ring-1 ring-black ring-opacity-5
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div class="relative grid bg-white">
|
<div class="relative grid bg-white dark:bg-gray-800">
|
||||||
<div class="relative p-4">
|
<div class="relative p-4">
|
||||||
<BaseInput
|
<BaseInput
|
||||||
v-model="textSearch"
|
v-model="textSearch"
|
||||||
@ -66,7 +72,7 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="filteredNotes.length > 0"
|
v-if="filteredNotes.length > 0"
|
||||||
class="relative flex flex-col overflow-auto list max-h-36"
|
class="relative flex flex-col overflow-auto list max-h-36 dark:border-white/10"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(note, index) in filteredNotes"
|
v-for="(note, index) in filteredNotes"
|
||||||
@ -79,6 +85,8 @@
|
|||||||
cursor-pointer
|
cursor-pointer
|
||||||
hover:bg-gray-100 hover:cursor-pointer
|
hover:bg-gray-100 hover:cursor-pointer
|
||||||
last:border-b-0
|
last:border-b-0
|
||||||
|
dark:border-gray-600
|
||||||
|
dark:border-white/10 dark:hover:bg-gray-700/30
|
||||||
"
|
"
|
||||||
@click="selectNote(index, close)"
|
@click="selectNote(index, close)"
|
||||||
>
|
>
|
||||||
@ -91,6 +99,7 @@
|
|||||||
leading-tight
|
leading-tight
|
||||||
text-gray-700
|
text-gray-700
|
||||||
cursor-pointer
|
cursor-pointer
|
||||||
|
dark:text-gray-400
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ note.name }}
|
{{ note.name }}
|
||||||
@ -118,6 +127,10 @@
|
|||||||
bg-gray-200
|
bg-gray-200
|
||||||
border-none
|
border-none
|
||||||
outline-none
|
outline-none
|
||||||
|
dark:bg-gray-600/70
|
||||||
|
dark:backdrop-blur-xl
|
||||||
|
dark:shadow-glass
|
||||||
|
dark:hover:bg-gray-600/80
|
||||||
"
|
"
|
||||||
@click="openNoteModal"
|
@click="openNoteModal"
|
||||||
>
|
>
|
||||||
|
|||||||
@ -6,8 +6,17 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import Chart from 'chart.js'
|
import Chart from 'chart.js'
|
||||||
import { ref, reactive, computed, onMounted, watchEffect, inject } from 'vue'
|
import {
|
||||||
|
ref,
|
||||||
|
reactive,
|
||||||
|
computed,
|
||||||
|
onMounted,
|
||||||
|
watchEffect,
|
||||||
|
inject,
|
||||||
|
watch,
|
||||||
|
} from 'vue'
|
||||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||||
|
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||||
|
|
||||||
const utils = inject('utils')
|
const utils = inject('utils')
|
||||||
|
|
||||||
@ -44,9 +53,11 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const isDarkModeOn = document.documentElement.classList.contains('dark')
|
||||||
let myLineChart = null
|
let myLineChart = null
|
||||||
const graph = ref(null)
|
const graph = ref(null)
|
||||||
const companyStore = useCompanyStore()
|
const companyStore = useCompanyStore()
|
||||||
|
const globalStore = useGlobalStore()
|
||||||
const defaultCurrency = computed(() => {
|
const defaultCurrency = computed(() => {
|
||||||
return companyStore.selectedCompanyCurrency
|
return companyStore.selectedCompanyCurrency
|
||||||
})
|
})
|
||||||
@ -60,6 +71,14 @@ watchEffect(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => globalStore.isDarkModeOn,
|
||||||
|
() => {
|
||||||
|
myLineChart.reset()
|
||||||
|
updateColors()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let context = graph.value.getContext('2d')
|
let context = graph.value.getContext('2d')
|
||||||
let options = reactive({
|
let options = reactive({
|
||||||
@ -81,6 +100,8 @@ onMounted(() => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const salesColor = globalStore.isDarkModeOn ? '#ffffff' : '#040405'
|
||||||
|
|
||||||
let data = reactive({
|
let data = reactive({
|
||||||
labels: props.labels,
|
labels: props.labels,
|
||||||
datasets: [
|
datasets: [
|
||||||
@ -89,16 +110,16 @@ onMounted(() => {
|
|||||||
fill: false,
|
fill: false,
|
||||||
lineTension: 0.3,
|
lineTension: 0.3,
|
||||||
backgroundColor: 'rgba(230, 254, 249)',
|
backgroundColor: 'rgba(230, 254, 249)',
|
||||||
borderColor: '#040405',
|
borderColor: salesColor,
|
||||||
borderCapStyle: 'butt',
|
borderCapStyle: 'butt',
|
||||||
borderDash: [],
|
borderDash: [],
|
||||||
borderDashOffset: 0.0,
|
borderDashOffset: 0.0,
|
||||||
borderJoinStyle: 'miter',
|
borderJoinStyle: 'miter',
|
||||||
pointBorderColor: '#040405',
|
pointBorderColor: salesColor,
|
||||||
pointBackgroundColor: '#fff',
|
pointBackgroundColor: '#fff',
|
||||||
pointBorderWidth: 1,
|
pointBorderWidth: 1,
|
||||||
pointHoverRadius: 5,
|
pointHoverRadius: 5,
|
||||||
pointHoverBackgroundColor: '#040405',
|
pointHoverBackgroundColor: salesColor,
|
||||||
pointHoverBorderColor: 'rgba(220,220,220,1)',
|
pointHoverBorderColor: 'rgba(220,220,220,1)',
|
||||||
pointHoverBorderWidth: 2,
|
pointHoverBorderWidth: 2,
|
||||||
pointRadius: 4,
|
pointRadius: 4,
|
||||||
@ -194,4 +215,12 @@ function update() {
|
|||||||
lazy: true,
|
lazy: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateColors() {
|
||||||
|
const newColor = globalStore.isDarkModeOn ? '#ffffff' : '#040405'
|
||||||
|
|
||||||
|
myLineChart.data.datasets[0].borderColor = newColor
|
||||||
|
myLineChart.data.datasets[0].pointBorderColor = newColor
|
||||||
|
myLineChart.data.datasets[0].pointHoverBackgroundColor = newColor
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -50,21 +50,11 @@
|
|||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
</template>
|
</template>
|
||||||
</ValidateEach>
|
</ValidateEach>
|
||||||
<div
|
<BaseModalFooter>
|
||||||
slot="footer"
|
|
||||||
class="
|
|
||||||
z-0
|
|
||||||
flex
|
|
||||||
justify-end
|
|
||||||
mt-4
|
|
||||||
pt-4
|
|
||||||
border-t border-gray-200 border-solid border-modal-bg
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<BaseButton :loading="isSaving" variant="primary" type="submit">
|
<BaseButton :loading="isSaving" variant="primary" type="submit">
|
||||||
{{ $t('general.save') }}
|
{{ $t('general.save') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseCard>
|
</BaseCard>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -64,7 +64,7 @@ function mergeExistingValues() {
|
|||||||
if (props.isEdit) {
|
if (props.isEdit) {
|
||||||
props.store[props.storeProp].fields.forEach((field) => {
|
props.store[props.storeProp].fields.forEach((field) => {
|
||||||
const existingIndex = props.store[props.storeProp].customFields.findIndex(
|
const existingIndex = props.store[props.storeProp].customFields.findIndex(
|
||||||
(f) => f.id === field.custom_field_id
|
(f) => f.id == field.custom_field_id
|
||||||
)
|
)
|
||||||
|
|
||||||
if (existingIndex > -1) {
|
if (existingIndex > -1) {
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { computed } from 'vue'
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: String,
|
type: String,
|
||||||
default: moment().format('YYYY-MM-DD hh:MM'),
|
default: moment().format('YYYY-MM-DD HH:mm'),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -7,11 +7,12 @@
|
|||||||
<!-- edit customField -->
|
<!-- edit customField -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.EDIT_CUSTOM_FIELDS)"
|
v-if="userStore.hasAbilities(abilities.EDIT_CUSTOM_FIELDS)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="editCustomField(row.id)"
|
@click="editCustomField(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PencilIcon"
|
name="PencilIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -19,11 +20,12 @@
|
|||||||
<!-- delete customField -->
|
<!-- delete customField -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.DELETE_CUSTOM_FIELDS)"
|
v-if="userStore.hasAbilities(abilities.DELETE_CUSTOM_FIELDS)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="removeCustomField(row.id)"
|
@click="removeCustomField(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|||||||
@ -12,10 +12,10 @@
|
|||||||
v-if="userStore.hasAbilities(abilities.EDIT_CUSTOMER)"
|
v-if="userStore.hasAbilities(abilities.EDIT_CUSTOMER)"
|
||||||
:to="`/admin/customers/${row.id}/edit`"
|
:to="`/admin/customers/${row.id}/edit`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PencilIcon"
|
name="PencilIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -29,10 +29,10 @@
|
|||||||
"
|
"
|
||||||
:to="`customers/${row.id}/view`"
|
:to="`customers/${row.id}/view`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="EyeIcon"
|
name="EyeIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.view') }}
|
{{ $t('general.view') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -41,11 +41,12 @@
|
|||||||
<!-- Delete Customer -->
|
<!-- Delete Customer -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.DELETE_CUSTOMER)"
|
v-if="userStore.hasAbilities(abilities.DELETE_CUSTOMER)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="removeCustomer(row.id)"
|
@click="removeCustomer(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|||||||
@ -10,11 +10,12 @@
|
|||||||
<!-- Copy PDF url -->
|
<!-- Copy PDF url -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="route.name === 'estimates.view'"
|
v-if="route.name === 'estimates.view'"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="copyPdfUrl"
|
@click="copyPdfUrl"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="LinkIcon"
|
name="LinkIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.copy_pdf_url') }}
|
{{ $t('general.copy_pdf_url') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -24,10 +25,10 @@
|
|||||||
v-if="userStore.hasAbilities(abilities.EDIT_ESTIMATE)"
|
v-if="userStore.hasAbilities(abilities.EDIT_ESTIMATE)"
|
||||||
:to="`/admin/estimates/${row.id}/edit`"
|
:to="`/admin/estimates/${row.id}/edit`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PencilIcon"
|
name="PencilIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -36,11 +37,12 @@
|
|||||||
<!-- Delete Estimate -->
|
<!-- Delete Estimate -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.DELETE_ESTIMATE)"
|
v-if="userStore.hasAbilities(abilities.DELETE_ESTIMATE)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="removeEstimate(row.id)"
|
@click="removeEstimate(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -53,10 +55,10 @@
|
|||||||
"
|
"
|
||||||
:to="`estimates/${row.id}/view`"
|
:to="`estimates/${row.id}/view`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="EyeIcon"
|
name="EyeIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.view') }}
|
{{ $t('general.view') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -65,11 +67,12 @@
|
|||||||
<!-- Convert into Invoice -->
|
<!-- Convert into Invoice -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.CREATE_INVOICE)"
|
v-if="userStore.hasAbilities(abilities.CREATE_INVOICE)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="convertInToinvoice(row.id)"
|
@click="convertInToinvoice(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="DocumentTextIcon"
|
name="DocumentTextIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('estimates.convert_to_invoice') }}
|
{{ $t('estimates.convert_to_invoice') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -81,11 +84,12 @@
|
|||||||
route.name !== 'estimates.view' &&
|
route.name !== 'estimates.view' &&
|
||||||
userStore.hasAbilities(abilities.SEND_ESTIMATE)
|
userStore.hasAbilities(abilities.SEND_ESTIMATE)
|
||||||
"
|
"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="onMarkAsSent(row.id)"
|
@click="onMarkAsSent(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="CheckCircleIcon"
|
name="CheckCircleIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('estimates.mark_as_sent') }}
|
{{ $t('estimates.mark_as_sent') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -97,20 +101,21 @@
|
|||||||
route.name !== 'estimates.view' &&
|
route.name !== 'estimates.view' &&
|
||||||
userStore.hasAbilities(abilities.SEND_ESTIMATE)
|
userStore.hasAbilities(abilities.SEND_ESTIMATE)
|
||||||
"
|
"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="sendEstimate(row)"
|
@click="sendEstimate(row)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PaperAirplaneIcon"
|
name="PaperAirplaneIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('estimates.send_estimate') }}
|
{{ $t('estimates.send_estimate') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|
||||||
<!-- Resend Estimate -->
|
<!-- Resend Estimate -->
|
||||||
<BaseDropdownItem v-if="canResendEstimate(row)" @click="sendEstimate(row)">
|
<BaseDropdownItem v-if="canResendEstimate(row)" v-slot="slotProps" @click="sendEstimate(row)">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PaperAirplaneIcon"
|
name="PaperAirplaneIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('estimates.resend_estimate') }}
|
{{ $t('estimates.resend_estimate') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -121,11 +126,12 @@
|
|||||||
row.status !== 'ACCEPTED' &&
|
row.status !== 'ACCEPTED' &&
|
||||||
userStore.hasAbilities(abilities.EDIT_ESTIMATE)
|
userStore.hasAbilities(abilities.EDIT_ESTIMATE)
|
||||||
"
|
"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="onMarkAsAccepted(row.id)"
|
@click="onMarkAsAccepted(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="CheckCircleIcon"
|
name="CheckCircleIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('estimates.mark_as_accepted') }}
|
{{ $t('estimates.mark_as_accepted') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -136,11 +142,12 @@
|
|||||||
row.status !== 'REJECTED' &&
|
row.status !== 'REJECTED' &&
|
||||||
userStore.hasAbilities(abilities.EDIT_ESTIMATE)
|
userStore.hasAbilities(abilities.EDIT_ESTIMATE)
|
||||||
"
|
"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="onMarkAsRejected(row.id)"
|
@click="onMarkAsRejected(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="XCircleIcon"
|
name="XCircleIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('estimates.mark_as_rejected') }}
|
{{ $t('estimates.mark_as_rejected') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|||||||
@ -13,11 +13,12 @@
|
|||||||
<!-- edit expenseCategory -->
|
<!-- edit expenseCategory -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.EDIT_EXPENSE)"
|
v-if="userStore.hasAbilities(abilities.EDIT_EXPENSE)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="editExpenseCategory(row.id)"
|
@click="editExpenseCategory(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PencilIcon"
|
name="PencilIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -25,11 +26,12 @@
|
|||||||
<!-- delete expenseCategory -->
|
<!-- delete expenseCategory -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.DELETE_EXPENSE)"
|
v-if="userStore.hasAbilities(abilities.DELETE_EXPENSE)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="removeExpenseCategory(row.id)"
|
@click="removeExpenseCategory(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|||||||
@ -12,10 +12,10 @@
|
|||||||
v-if="userStore.hasAbilities(abilities.EDIT_EXPENSE)"
|
v-if="userStore.hasAbilities(abilities.EDIT_EXPENSE)"
|
||||||
:to="`/admin/expenses/${row.id}/edit`"
|
:to="`/admin/expenses/${row.id}/edit`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PencilIcon"
|
name="PencilIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -24,11 +24,12 @@
|
|||||||
<!-- delete expense -->
|
<!-- delete expense -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.DELETE_EXPENSE)"
|
v-if="userStore.hasAbilities(abilities.DELETE_EXPENSE)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="removeExpense(row.id)"
|
@click="removeExpense(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|||||||
@ -12,20 +12,20 @@
|
|||||||
v-if="userStore.hasAbilities(abilities.EDIT_INVOICE)"
|
v-if="userStore.hasAbilities(abilities.EDIT_INVOICE)"
|
||||||
:to="`/admin/invoices/${row.id}/edit`"
|
:to="`/admin/invoices/${row.id}/edit`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem v-show="row.allow_edit">
|
<BaseDropdownItem v-show="row.allow_edit" v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PencilIcon"
|
name="PencilIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<!-- Copy PDF url -->
|
<!-- Copy PDF url -->
|
||||||
<BaseDropdownItem v-if="route.name === 'invoices.view'" @click="copyPdfUrl">
|
<BaseDropdownItem v-if="route.name === 'invoices.view'" v-slot="slotProps" @click="copyPdfUrl">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="LinkIcon"
|
name="LinkIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.copy_pdf_url') }}
|
{{ $t('general.copy_pdf_url') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -38,29 +38,29 @@
|
|||||||
"
|
"
|
||||||
:to="`/admin/invoices/${row.id}/view`"
|
:to="`/admin/invoices/${row.id}/view`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="EyeIcon"
|
name="EyeIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.view') }}
|
{{ $t('general.view') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<!-- Send Invoice Mail -->
|
<!-- Send Invoice Mail -->
|
||||||
<BaseDropdownItem v-if="canSendInvoice(row)" @click="sendInvoice(row)">
|
<BaseDropdownItem v-if="canSendInvoice(row)" v-slot="slotProps" @click="sendInvoice(row)">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PaperAirplaneIcon"
|
name="PaperAirplaneIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('invoices.send_invoice') }}
|
{{ $t('invoices.send_invoice') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|
||||||
<!-- Resend Invoice -->
|
<!-- Resend Invoice -->
|
||||||
<BaseDropdownItem v-if="canReSendInvoice(row)" @click="sendInvoice(row)">
|
<BaseDropdownItem v-if="canReSendInvoice(row)" v-slot="slotProps" @click="sendInvoice(row)">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PaperAirplaneIcon"
|
name="PaperAirplaneIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('invoices.resend_invoice') }}
|
{{ $t('invoices.resend_invoice') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -69,20 +69,21 @@
|
|||||||
<router-link :to="`/admin/payments/${row.id}/create`">
|
<router-link :to="`/admin/payments/${row.id}/create`">
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="row.status == 'SENT' && route.name !== 'invoices.view'"
|
v-if="row.status == 'SENT' && route.name !== 'invoices.view'"
|
||||||
|
v-slot="slotProps"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="CreditCardIcon"
|
name="CreditCardIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('invoices.record_payment') }}
|
{{ $t('invoices.record_payment') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<!-- Mark as sent Invoice -->
|
<!-- Mark as sent Invoice -->
|
||||||
<BaseDropdownItem v-if="canSendInvoice(row)" @click="onMarkAsSent(row.id)">
|
<BaseDropdownItem v-if="canSendInvoice(row)" v-slot="slotProps" @click="onMarkAsSent(row.id)">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="CheckCircleIcon"
|
name="CheckCircleIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('invoices.mark_as_sent') }}
|
{{ $t('invoices.mark_as_sent') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -90,11 +91,12 @@
|
|||||||
<!-- Clone Invoice into new invoice -->
|
<!-- Clone Invoice into new invoice -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.CREATE_INVOICE)"
|
v-if="userStore.hasAbilities(abilities.CREATE_INVOICE)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="cloneInvoiceData(row)"
|
@click="cloneInvoiceData(row)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="DocumentTextIcon"
|
name="DocumentTextIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('invoices.clone_invoice') }}
|
{{ $t('invoices.clone_invoice') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -102,11 +104,12 @@
|
|||||||
<!-- Delete Invoice -->
|
<!-- Delete Invoice -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.DELETE_INVOICE)"
|
v-if="userStore.hasAbilities(abilities.DELETE_INVOICE)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="removeInvoice(row.id)"
|
@click="removeInvoice(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|||||||
@ -12,11 +12,8 @@
|
|||||||
v-if="userStore.hasAbilities(abilities.EDIT_ITEM)"
|
v-if="userStore.hasAbilities(abilities.EDIT_ITEM)"
|
||||||
:to="`/admin/items/${row.id}/edit`"
|
:to="`/admin/items/${row.id}/edit`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon name="PencilIcon" :class="slotProps.class" />
|
||||||
name="PencilIcon"
|
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
|
||||||
/>
|
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</router-link>
|
</router-link>
|
||||||
@ -24,12 +21,10 @@
|
|||||||
<!-- delete item -->
|
<!-- delete item -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.DELETE_ITEM)"
|
v-if="userStore.hasAbilities(abilities.DELETE_ITEM)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="removeItem(row.id)"
|
@click="removeItem(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon name="TrashIcon" :class="slotProps.class" />
|
||||||
name="TrashIcon"
|
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
|
||||||
/>
|
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</BaseDropdown>
|
</BaseDropdown>
|
||||||
|
|||||||
@ -10,11 +10,12 @@
|
|||||||
<!-- edit note -->
|
<!-- edit note -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.MANAGE_NOTE)"
|
v-if="userStore.hasAbilities(abilities.MANAGE_NOTE)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="editNote(row.id)"
|
@click="editNote(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PencilIcon"
|
name="PencilIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -22,11 +23,12 @@
|
|||||||
<!-- delete note -->
|
<!-- delete note -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.MANAGE_NOTE)"
|
v-if="userStore.hasAbilities(abilities.MANAGE_NOTE)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="removeNote(row.id)"
|
@click="removeNote(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|||||||
@ -8,30 +8,31 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Copy pdf url -->
|
<!-- Copy pdf url -->
|
||||||
<BaseDropdown-item
|
<BaseDropdownItem
|
||||||
v-if="
|
v-if="
|
||||||
route.name === 'payments.view' &&
|
route.name === 'payments.view' &&
|
||||||
userStore.hasAbilities(abilities.VIEW_PAYMENT)
|
userStore.hasAbilities(abilities.VIEW_PAYMENT)
|
||||||
"
|
"
|
||||||
|
v-slot="slotProps"
|
||||||
class="rounded-md"
|
class="rounded-md"
|
||||||
@click="copyPdfUrl"
|
@click="copyPdfUrl"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="LinkIcon"
|
name="LinkIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.copy_pdf_url') }}
|
{{ $t('general.copy_pdf_url') }}
|
||||||
</BaseDropdown-item>
|
</BaseDropdownItem>
|
||||||
|
|
||||||
<!-- edit payment -->
|
<!-- edit payment -->
|
||||||
<router-link
|
<router-link
|
||||||
v-if="userStore.hasAbilities(abilities.EDIT_PAYMENT)"
|
v-if="userStore.hasAbilities(abilities.EDIT_PAYMENT)"
|
||||||
:to="`/admin/payments/${row.id}/edit`"
|
:to="`/admin/payments/${row.id}/edit`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PencilIcon"
|
name="PencilIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -45,10 +46,10 @@
|
|||||||
"
|
"
|
||||||
:to="`/admin/payments/${row.id}/view`"
|
:to="`/admin/payments/${row.id}/view`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="EyeIcon"
|
name="EyeIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.view') }}
|
{{ $t('general.view') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -61,11 +62,12 @@
|
|||||||
route.name !== 'payments.view' &&
|
route.name !== 'payments.view' &&
|
||||||
userStore.hasAbilities(abilities.SEND_PAYMENT)
|
userStore.hasAbilities(abilities.SEND_PAYMENT)
|
||||||
"
|
"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="sendPayment(row)"
|
@click="sendPayment(row)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PaperAirplaneIcon"
|
name="PaperAirplaneIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('payments.send_payment') }}
|
{{ $t('payments.send_payment') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -73,11 +75,12 @@
|
|||||||
<!-- delete payment -->
|
<!-- delete payment -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.DELETE_PAYMENT)"
|
v-if="userStore.hasAbilities(abilities.DELETE_PAYMENT)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="removePayment(row.id)"
|
@click="removePayment(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|||||||
@ -8,19 +8,19 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- edit paymentMode -->
|
<!-- edit paymentMode -->
|
||||||
<BaseDropdownItem @click="editPaymentMode(row.id)">
|
<BaseDropdownItem v-slot="slotProps" @click="editPaymentMode(row.id)">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PencilIcon"
|
name="PencilIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|
||||||
<!-- delete paymentMode -->
|
<!-- delete paymentMode -->
|
||||||
<BaseDropdownItem @click="removePaymentMode(row.id)">
|
<BaseDropdownItem v-slot="slotProps" @click="removePaymentMode(row.id)">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|||||||
@ -15,10 +15,10 @@
|
|||||||
v-if="userStore.hasAbilities(abilities.EDIT_RECURRING_INVOICE)"
|
v-if="userStore.hasAbilities(abilities.EDIT_RECURRING_INVOICE)"
|
||||||
:to="`/admin/recurring-invoices/${row.id}/edit`"
|
:to="`/admin/recurring-invoices/${row.id}/edit`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PencilIcon"
|
name="PencilIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -32,10 +32,10 @@
|
|||||||
"
|
"
|
||||||
:to="`recurring-invoices/${row.id}/view`"
|
:to="`recurring-invoices/${row.id}/view`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="EyeIcon"
|
name="EyeIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.view') }}
|
{{ $t('general.view') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -44,11 +44,12 @@
|
|||||||
<!-- Delete Recurring Invoice -->
|
<!-- Delete Recurring Invoice -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.DELETE_RECURRING_INVOICE)"
|
v-if="userStore.hasAbilities(abilities.DELETE_RECURRING_INVOICE)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="removeMultipleRecurringInvoices(row.id)"
|
@click="removeMultipleRecurringInvoices(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|||||||
@ -10,11 +10,12 @@
|
|||||||
<!-- edit role -->
|
<!-- edit role -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.currentUser.is_owner"
|
v-if="userStore.currentUser.is_owner"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="editRole(row.id)"
|
@click="editRole(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PencilIcon"
|
name="PencilIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -22,11 +23,12 @@
|
|||||||
<!-- delete role -->
|
<!-- delete role -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.currentUser.is_owner"
|
v-if="userStore.currentUser.is_owner"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="removeRole(row.id)"
|
@click="removeRole(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|||||||
@ -10,11 +10,12 @@
|
|||||||
<!-- edit tax-type -->
|
<!-- edit tax-type -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.EDIT_TAX_TYPE)"
|
v-if="userStore.hasAbilities(abilities.EDIT_TAX_TYPE)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="editTaxType(row.id)"
|
@click="editTaxType(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PencilIcon"
|
name="PencilIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
@ -22,11 +23,12 @@
|
|||||||
<!-- delete tax-type -->
|
<!-- delete tax-type -->
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.DELETE_TAX_TYPE)"
|
v-if="userStore.hasAbilities(abilities.DELETE_TAX_TYPE)"
|
||||||
|
v-slot="slotProps"
|
||||||
@click="removeTaxType(row.id)"
|
@click="removeTaxType(row.id)"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|||||||
@ -9,20 +9,20 @@
|
|||||||
|
|
||||||
<!-- edit user -->
|
<!-- edit user -->
|
||||||
<router-link :to="`/admin/users/${row.id}/edit`">
|
<router-link :to="`/admin/users/${row.id}/edit`">
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="PencilIcon"
|
name="PencilIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.edit') }}
|
{{ $t('general.edit') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<!-- delete user -->
|
<!-- delete user -->
|
||||||
<BaseDropdownItem @click="removeUser(row.id)">
|
<BaseDropdownItem v-slot="slotProps" @click="removeUser(row.id)">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
/>
|
/>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
|
|||||||
@ -1,5 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<tr class="box-border bg-white border border-gray-200 border-solid rounded-b">
|
<tr
|
||||||
|
class="
|
||||||
|
box-border
|
||||||
|
bg-white
|
||||||
|
border border-gray-200 border-solid
|
||||||
|
rounded-b
|
||||||
|
dark:shadow-glass dark:border dark:border-white/10 dark:bg-gray-800/70
|
||||||
|
"
|
||||||
|
>
|
||||||
<td colspan="5" class="p-0 text-left align-top">
|
<td colspan="5" class="p-0 text-left align-top">
|
||||||
<table class="w-full">
|
<table class="w-full">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
@ -130,7 +138,7 @@
|
|||||||
<div class="flex items-center justify-center w-6 h-10 mx-2">
|
<div class="flex items-center justify-center w-6 h-10 mx-2">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
v-if="showRemoveButton"
|
v-if="showRemoveButton"
|
||||||
class="h-5 text-gray-700 cursor-pointer"
|
class="h-5 dark:text-red-400 cursor-pointer"
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
@click="store.removeItem(index)"
|
@click="store.removeItem(index)"
|
||||||
/>
|
/>
|
||||||
@ -271,19 +279,23 @@ const price = computed({
|
|||||||
} else {
|
} else {
|
||||||
updateItemAttribute('price', newValue)
|
updateItemAttribute('price', newValue)
|
||||||
}
|
}
|
||||||
setDiscount()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const subtotal = computed(() => Math.round(props.itemData.price * props.itemData.quantity))
|
const subtotal = computed(() => props.itemData.price * props.itemData.quantity)
|
||||||
|
|
||||||
const discount = computed({
|
const discount = computed({
|
||||||
get: () => {
|
get: () => {
|
||||||
return props.itemData.discount
|
return props.itemData.discount
|
||||||
},
|
},
|
||||||
set: (newValue) => {
|
set: (newValue) => {
|
||||||
|
if (props.itemData.discount_type === 'percentage') {
|
||||||
|
updateItemAttribute('discount_val', (subtotal.value * newValue) / 100)
|
||||||
|
} else {
|
||||||
|
updateItemAttribute('discount_val', Math.round(newValue * 100))
|
||||||
|
}
|
||||||
|
|
||||||
updateItemAttribute('discount', newValue)
|
updateItemAttribute('discount', newValue)
|
||||||
setDiscount()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -309,7 +321,7 @@ const showRemoveButton = computed(() => {
|
|||||||
const totalSimpleTax = computed(() => {
|
const totalSimpleTax = computed(() => {
|
||||||
return Math.round(
|
return Math.round(
|
||||||
sumBy(props.itemData.taxes, function (tax) {
|
sumBy(props.itemData.taxes, function (tax) {
|
||||||
if (tax.amount) {
|
if (!tax.compound_tax) {
|
||||||
return tax.amount
|
return tax.amount
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
@ -317,7 +329,18 @@ const totalSimpleTax = computed(() => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const totalTax = computed(() => totalSimpleTax.value)
|
const totalCompoundTax = computed(() => {
|
||||||
|
return Math.round(
|
||||||
|
sumBy(props.itemData.taxes, function (tax) {
|
||||||
|
if (tax.compound_tax) {
|
||||||
|
return tax.amount
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const totalTax = computed(() => totalSimpleTax.value + totalCompoundTax.value)
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
name: {
|
name: {
|
||||||
@ -384,7 +407,7 @@ const v$ = useVuelidate(
|
|||||||
|
|
||||||
function updateTax(data) {
|
function updateTax(data) {
|
||||||
props.store.$patch((state) => {
|
props.store.$patch((state) => {
|
||||||
state[props.storeProp].items[props.index]['taxes'][data.index] = data.item
|
state[props.storeProp].items[props.index]['taxes'][data.index] = data.item
|
||||||
})
|
})
|
||||||
|
|
||||||
let lastTax = props.itemData.taxes[props.itemData.taxes.length - 1]
|
let lastTax = props.itemData.taxes[props.itemData.taxes.length - 1]
|
||||||
@ -401,16 +424,6 @@ function updateTax(data) {
|
|||||||
syncItemToStore()
|
syncItemToStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
function setDiscount() {
|
|
||||||
const newValue = props.store[props.storeProp].items[props.index].discount
|
|
||||||
|
|
||||||
if (props.itemData.discount_type === 'percentage'){
|
|
||||||
updateItemAttribute('discount_val', Math.round((subtotal.value * newValue) / 100))
|
|
||||||
}else{
|
|
||||||
updateItemAttribute('discount_val', Math.round(newValue * 100))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function searchVal(val) {
|
function searchVal(val) {
|
||||||
updateItemAttribute('name', val)
|
updateItemAttribute('name', val)
|
||||||
}
|
}
|
||||||
@ -480,12 +493,10 @@ function syncItemToStore() {
|
|||||||
total: total.value,
|
total: total.value,
|
||||||
sub_total: subtotal.value,
|
sub_total: subtotal.value,
|
||||||
totalSimpleTax: totalSimpleTax.value,
|
totalSimpleTax: totalSimpleTax.value,
|
||||||
|
totalCompoundTax: totalCompoundTax.value,
|
||||||
totalTax: totalTax.value,
|
totalTax: totalTax.value,
|
||||||
tax: totalTax.value,
|
tax: totalTax.value,
|
||||||
taxes: [...itemTaxes],
|
taxes: [...itemTaxes],
|
||||||
tax_type_ids: itemTaxes.flatMap(_t =>
|
|
||||||
_t.tax_type_id ? _t.tax_type_id : [],
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
props.store.updateItem(data)
|
props.store.updateItem(data)
|
||||||
|
|||||||
@ -30,7 +30,22 @@
|
|||||||
<template v-if="userStore.hasAbilities(ability)" #action>
|
<template v-if="userStore.hasAbilities(ability)" #action>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="flex items-center justify-center w-full px-2 py-2 bg-gray-200 border-none outline-none cursor-pointer "
|
class="
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
justify-center
|
||||||
|
w-full
|
||||||
|
px-2
|
||||||
|
py-2
|
||||||
|
bg-gray-200
|
||||||
|
border-none
|
||||||
|
outline-none
|
||||||
|
cursor-pointer
|
||||||
|
dark:bg-gray-600/70
|
||||||
|
dark:backdrop-blur-xl
|
||||||
|
dark:shadow-glass
|
||||||
|
dark:hover:bg-gray-600/80
|
||||||
|
"
|
||||||
@click="openTaxModal"
|
@click="openTaxModal"
|
||||||
>
|
>
|
||||||
<BaseIcon name="CheckCircleIcon" class="h-5 text-primary-400" />
|
<BaseIcon name="CheckCircleIcon" class="h-5 text-primary-400" />
|
||||||
@ -53,7 +68,7 @@
|
|||||||
<BaseIcon
|
<BaseIcon
|
||||||
v-if="taxes.length && index !== taxes.length - 1"
|
v-if="taxes.length && index !== taxes.length - 1"
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="h-5 text-gray-700 cursor-pointer"
|
class="h-5 text-gray-700 dark:text-red-400 cursor-pointer"
|
||||||
@click="removeTax(index)"
|
@click="removeTax(index)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -146,14 +161,14 @@ const filteredTypes = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const taxAmount = computed(() => {
|
const taxAmount = computed(() => {
|
||||||
|
if (localTax.compound_tax && props.discountedTotal) {
|
||||||
|
return ((props.discountedTotal + props.totalTax) * localTax.percent) / 100
|
||||||
|
}
|
||||||
|
|
||||||
if (props.discountedTotal && localTax.percent) {
|
if (props.discountedTotal && localTax.percent) {
|
||||||
const taxPerItemEnabled = props.store[props.storeProp].tax_per_item === 'YES'
|
|
||||||
const discountPerItemEnabled = props.store[props.storeProp].discount_per_item === 'YES'
|
|
||||||
if (taxPerItemEnabled && !discountPerItemEnabled){
|
|
||||||
return getTaxAmount()
|
|
||||||
}
|
|
||||||
return (props.discountedTotal * localTax.percent) / 100
|
return (props.discountedTotal * localTax.percent) / 100
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -171,13 +186,6 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
watch(
|
|
||||||
() => taxAmount.value,
|
|
||||||
() => {
|
|
||||||
updateRowTax()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
// Set SelectedTax
|
// Set SelectedTax
|
||||||
if (props.taxData.tax_type_id > 0) {
|
if (props.taxData.tax_type_id > 0) {
|
||||||
selectedTax.value = taxTypeStore.taxTypes.find(
|
selectedTax.value = taxTypeStore.taxTypes.find(
|
||||||
@ -190,6 +198,7 @@ updateRowTax()
|
|||||||
function onSelectTax(val) {
|
function onSelectTax(val) {
|
||||||
localTax.percent = val.percent
|
localTax.percent = val.percent
|
||||||
localTax.tax_type_id = val.id
|
localTax.tax_type_id = val.id
|
||||||
|
localTax.compound_tax = val.compound_tax
|
||||||
localTax.name = val.name
|
localTax.name = val.name
|
||||||
|
|
||||||
updateRowTax()
|
updateRowTax()
|
||||||
@ -226,27 +235,6 @@ function openTaxModal() {
|
|||||||
function removeTax(index) {
|
function removeTax(index) {
|
||||||
props.store.$patch((state) => {
|
props.store.$patch((state) => {
|
||||||
state[props.storeProp].items[props.itemIndex].taxes.splice(index, 1)
|
state[props.storeProp].items[props.itemIndex].taxes.splice(index, 1)
|
||||||
state[props.storeProp].items[props.itemIndex].tax = 0
|
|
||||||
state[props.storeProp].items[props.itemIndex].totalTax = 0
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTaxAmount() {
|
|
||||||
let total = 0
|
|
||||||
let discount = 0
|
|
||||||
const itemTotal = props.discountedTotal
|
|
||||||
const modelDiscount = props.store[props.storeProp].discount ? props.store[props.storeProp].discount : 0
|
|
||||||
const type = props.store[props.storeProp].discount_type
|
|
||||||
if (modelDiscount > 0) {
|
|
||||||
props.store[props.storeProp].items.forEach((_i) => {
|
|
||||||
total += _i.total
|
|
||||||
})
|
|
||||||
const proportion = (itemTotal / total).toFixed(2)
|
|
||||||
discount = type === 'fixed' ? modelDiscount * 100 : (total * modelDiscount) / 100
|
|
||||||
const itemDiscount = Math.round(discount * proportion)
|
|
||||||
const discounted = itemTotal - itemDiscount
|
|
||||||
return Math.round((discounted * localTax.percent) / 100)
|
|
||||||
}
|
|
||||||
return Math.round((props.discountedTotal * localTax.percent) / 100)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,155 +1,172 @@
|
|||||||
<template>
|
<template>
|
||||||
<table class="text-center item-table min-w-full">
|
<div class="relative" >
|
||||||
<colgroup>
|
<BaseDarkHighlight class="z-[-1]" />
|
||||||
<col style="width: 40%; min-width: 280px" />
|
<table class="text-center item-table min-w-full">
|
||||||
<col style="width: 10%; min-width: 120px" />
|
<colgroup>
|
||||||
<col style="width: 15%; min-width: 120px" />
|
<col style="width: 40%; min-width: 280px" />
|
||||||
<col
|
<col style="width: 10%; min-width: 120px" />
|
||||||
v-if="store[storeProp].discount_per_item === 'YES'"
|
<col style="width: 15%; min-width: 120px" />
|
||||||
style="width: 15%; min-width: 160px"
|
<col
|
||||||
/>
|
|
||||||
<col style="width: 15%; min-width: 120px" />
|
|
||||||
</colgroup>
|
|
||||||
<thead class="bg-white border border-gray-200 border-solid">
|
|
||||||
<tr>
|
|
||||||
<th
|
|
||||||
class="
|
|
||||||
px-5
|
|
||||||
py-3
|
|
||||||
text-sm
|
|
||||||
not-italic
|
|
||||||
font-medium
|
|
||||||
leading-5
|
|
||||||
text-left text-gray-700
|
|
||||||
border-t border-b border-gray-200 border-solid
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<BaseContentPlaceholders v-if="isLoading">
|
|
||||||
<BaseContentPlaceholdersText :lines="1" class="w-16 h-5" />
|
|
||||||
</BaseContentPlaceholders>
|
|
||||||
<span v-else class="pl-7">
|
|
||||||
{{ $tc('items.item', 2) }}
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="
|
|
||||||
px-5
|
|
||||||
py-3
|
|
||||||
text-sm
|
|
||||||
not-italic
|
|
||||||
font-medium
|
|
||||||
leading-5
|
|
||||||
text-right text-gray-700
|
|
||||||
border-t border-b border-gray-200 border-solid
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<BaseContentPlaceholders v-if="isLoading">
|
|
||||||
<BaseContentPlaceholdersText :lines="1" class="w-16 h-5" />
|
|
||||||
</BaseContentPlaceholders>
|
|
||||||
<span v-else>
|
|
||||||
{{ $t('invoices.item.quantity') }}
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="
|
|
||||||
px-5
|
|
||||||
py-3
|
|
||||||
text-sm
|
|
||||||
not-italic
|
|
||||||
font-medium
|
|
||||||
leading-5
|
|
||||||
text-left text-gray-700
|
|
||||||
border-t border-b border-gray-200 border-solid
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<BaseContentPlaceholders v-if="isLoading">
|
|
||||||
<BaseContentPlaceholdersText :lines="1" class="w-16 h-5" />
|
|
||||||
</BaseContentPlaceholders>
|
|
||||||
<span v-else>
|
|
||||||
{{ $t('invoices.item.price') }}
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
v-if="store[storeProp].discount_per_item === 'YES'"
|
v-if="store[storeProp].discount_per_item === 'YES'"
|
||||||
class="
|
style="width: 15%; min-width: 160px"
|
||||||
px-5
|
|
||||||
py-3
|
|
||||||
text-sm
|
|
||||||
not-italic
|
|
||||||
font-medium
|
|
||||||
leading-5
|
|
||||||
text-left text-gray-700
|
|
||||||
border-t border-b border-gray-200 border-solid
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<BaseContentPlaceholders v-if="isLoading">
|
|
||||||
<BaseContentPlaceholdersText :lines="1" class="w-16 h-5" />
|
|
||||||
</BaseContentPlaceholders>
|
|
||||||
<span v-else>
|
|
||||||
{{ $t('invoices.item.discount') }}
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
class="
|
|
||||||
px-5
|
|
||||||
py-3
|
|
||||||
text-sm
|
|
||||||
not-italic
|
|
||||||
font-medium
|
|
||||||
leading-5
|
|
||||||
text-right text-gray-700
|
|
||||||
border-t border-b border-gray-200 border-solid
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<BaseContentPlaceholders v-if="isLoading">
|
|
||||||
<BaseContentPlaceholdersText :lines="1" class="w-16 h-5" />
|
|
||||||
</BaseContentPlaceholders>
|
|
||||||
<span v-else class="pr-10 column-heading">
|
|
||||||
{{ $t('invoices.item.amount') }}
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<draggable
|
|
||||||
v-model="store[storeProp].items"
|
|
||||||
item-key="id"
|
|
||||||
tag="tbody"
|
|
||||||
handle=".handle"
|
|
||||||
>
|
|
||||||
<template #item="{ element, index }">
|
|
||||||
<Item
|
|
||||||
:key="element.id"
|
|
||||||
:index="index"
|
|
||||||
:item-data="element"
|
|
||||||
:loading="isLoading"
|
|
||||||
:currency="defaultCurrency"
|
|
||||||
:item-validation-scope="itemValidationScope"
|
|
||||||
:invoice-items="store[storeProp].items"
|
|
||||||
:store="store"
|
|
||||||
:store-prop="storeProp"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
<col style="width: 15%; min-width: 120px" />
|
||||||
</draggable>
|
</colgroup>
|
||||||
</table>
|
<thead
|
||||||
|
class="
|
||||||
|
bg-white
|
||||||
|
border
|
||||||
|
border-gray-200
|
||||||
|
border-solid
|
||||||
|
dark:shadow-glass dark:border dark:border-white/10 dark:bg-gray-800/70
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
class="
|
||||||
|
px-5
|
||||||
|
py-3
|
||||||
|
text-sm
|
||||||
|
not-italic
|
||||||
|
font-medium
|
||||||
|
leading-5
|
||||||
|
text-left text-gray-700
|
||||||
|
border-t border-b border-gray-200 border-solid
|
||||||
|
dark:text-white dark:border-white/10
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<BaseContentPlaceholders v-if="isLoading">
|
||||||
|
<BaseContentPlaceholdersText :lines="1" class="w-16 h-5" />
|
||||||
|
</BaseContentPlaceholders>
|
||||||
|
<span v-else class="pl-7">
|
||||||
|
{{ $tc('items.item', 2) }}
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="
|
||||||
|
px-5
|
||||||
|
py-3
|
||||||
|
text-sm
|
||||||
|
not-italic
|
||||||
|
font-medium
|
||||||
|
leading-5
|
||||||
|
text-right text-gray-700
|
||||||
|
border-t border-b border-gray-200 border-solid
|
||||||
|
dark:text-white dark:border-white/10
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<BaseContentPlaceholders v-if="isLoading">
|
||||||
|
<BaseContentPlaceholdersText :lines="1" class="w-16 h-5" />
|
||||||
|
</BaseContentPlaceholders>
|
||||||
|
<span v-else>
|
||||||
|
{{ $t('invoices.item.quantity') }}
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="
|
||||||
|
px-5
|
||||||
|
py-3
|
||||||
|
text-sm
|
||||||
|
not-italic
|
||||||
|
font-medium
|
||||||
|
leading-5
|
||||||
|
text-left text-gray-700
|
||||||
|
border-t border-b border-gray-200 border-solid
|
||||||
|
dark:text-white dark:border-white/10
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<BaseContentPlaceholders v-if="isLoading">
|
||||||
|
<BaseContentPlaceholdersText :lines="1" class="w-16 h-5" />
|
||||||
|
</BaseContentPlaceholders>
|
||||||
|
<span v-else>
|
||||||
|
{{ $t('invoices.item.price') }}
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
v-if="store[storeProp].discount_per_item === 'YES'"
|
||||||
|
class="
|
||||||
|
px-5
|
||||||
|
py-3
|
||||||
|
text-sm
|
||||||
|
not-italic
|
||||||
|
font-medium
|
||||||
|
leading-5
|
||||||
|
text-left text-gray-700
|
||||||
|
border-t border-b border-gray-200 border-solid
|
||||||
|
dark:text-white dark:border-white/10
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<BaseContentPlaceholders v-if="isLoading">
|
||||||
|
<BaseContentPlaceholdersText :lines="1" class="w-16 h-5" />
|
||||||
|
</BaseContentPlaceholders>
|
||||||
|
<span v-else>
|
||||||
|
{{ $t('invoices.item.discount') }}
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="
|
||||||
|
px-5
|
||||||
|
py-3
|
||||||
|
text-sm
|
||||||
|
not-italic
|
||||||
|
font-medium
|
||||||
|
leading-5
|
||||||
|
text-right text-gray-700
|
||||||
|
border-t border-b border-gray-200 border-solid
|
||||||
|
dark:text-white dark:border-white/10
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<BaseContentPlaceholders v-if="isLoading">
|
||||||
|
<BaseContentPlaceholdersText :lines="1" class="w-16 h-5" />
|
||||||
|
</BaseContentPlaceholders>
|
||||||
|
<span v-else class="pr-10 column-heading">
|
||||||
|
{{ $t('invoices.item.amount') }}
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<draggable
|
||||||
|
v-model="store[storeProp].items"
|
||||||
|
item-key="id"
|
||||||
|
tag="tbody"
|
||||||
|
handle=".handle"
|
||||||
|
>
|
||||||
|
<template #item="{ element, index }">
|
||||||
|
<Item
|
||||||
|
:key="element.id"
|
||||||
|
:index="index"
|
||||||
|
:item-data="element"
|
||||||
|
:loading="isLoading"
|
||||||
|
:currency="defaultCurrency"
|
||||||
|
:item-validation-scope="itemValidationScope"
|
||||||
|
:invoice-items="store[storeProp].items"
|
||||||
|
:store="store"
|
||||||
|
:store-prop="storeProp"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
</table>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="
|
class="
|
||||||
flex
|
flex
|
||||||
items-center
|
items-center
|
||||||
justify-center
|
justify-center
|
||||||
w-full
|
w-full
|
||||||
px-6
|
px-6
|
||||||
py-3
|
py-3
|
||||||
text-base
|
text-base
|
||||||
border border-t-0 border-gray-200 border-solid
|
border border-t-0 border-gray-200 border-solid
|
||||||
cursor-pointer
|
cursor-pointer
|
||||||
text-primary-400
|
text-primary-400
|
||||||
hover:bg-primary-100
|
hover:bg-primary-100
|
||||||
"
|
dark:bg-gray-900/50 dark:border-white/10 dark:hover:bg-gray-900/80
|
||||||
@click="store.addItem"
|
"
|
||||||
>
|
@click="store.addItem"
|
||||||
<BaseIcon name="PlusCircleIcon" class="mr-2" />
|
>
|
||||||
{{ $t('general.add_new_item') }}
|
<BaseIcon name="PlusCircleIcon" class="mr-2" />
|
||||||
|
{{ $t('general.add_new_item') }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
>
|
>
|
||||||
<SelectNotePopup :type="type" @select="onSelectNote" />
|
<SelectNotePopup :type="type" @select="onSelectNote" />
|
||||||
</div>
|
</div>
|
||||||
<label class="text-gray-800 font-medium mb-4 text-sm">
|
<label class="text-gray-800 font-medium mb-4 text-sm dark:text-gray-300">
|
||||||
{{ $t('invoices.notes') }}
|
{{ $t('invoices.notes') }}
|
||||||
</label>
|
</label>
|
||||||
<BaseCustomInput
|
<BaseCustomInput
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
mt-6
|
mt-6
|
||||||
bg-white
|
bg-white
|
||||||
border border-gray-200 border-solid
|
border border-gray-200 border-solid
|
||||||
|
dark:bg-gray-800/50 dark:border-white/10
|
||||||
rounded
|
rounded
|
||||||
md:min-w-[390px]
|
md:min-w-[390px]
|
||||||
min-w-[300px]
|
min-w-[300px]
|
||||||
@ -29,7 +30,16 @@
|
|||||||
|
|
||||||
<label
|
<label
|
||||||
v-else
|
v-else
|
||||||
class="flex items-center justify-center m-0 text-lg text-black uppercase "
|
class="
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
justify-center
|
||||||
|
m-0
|
||||||
|
text-lg
|
||||||
|
text-black
|
||||||
|
dark:text-white
|
||||||
|
uppercase
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<BaseFormatMoney
|
<BaseFormatMoney
|
||||||
:amount="store.getSubTotal"
|
:amount="store.getSubTotal"
|
||||||
@ -59,7 +69,16 @@
|
|||||||
|
|
||||||
<label
|
<label
|
||||||
v-else-if="store[storeProp].tax_per_item === 'YES'"
|
v-else-if="store[storeProp].tax_per_item === 'YES'"
|
||||||
class="flex items-center justify-center m-0 text-lg text-black uppercase "
|
class="
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
justify-center
|
||||||
|
m-0
|
||||||
|
text-lg
|
||||||
|
text-black
|
||||||
|
dark:text-white
|
||||||
|
uppercase
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<BaseFormatMoney :amount="tax.amount" :currency="defaultCurrency" />
|
<BaseFormatMoney :amount="tax.amount" :currency="defaultCurrency" />
|
||||||
</label>
|
</label>
|
||||||
@ -166,14 +185,23 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-between w-full pt-2 mt-5 border-t border-gray-200 border-solid "
|
class="
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
justify-between
|
||||||
|
w-full
|
||||||
|
pt-2
|
||||||
|
mt-5
|
||||||
|
border-t border-gray-200 border-solid
|
||||||
|
dark:border-gray-600
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<BaseContentPlaceholders v-if="isLoading">
|
<BaseContentPlaceholders v-if="isLoading">
|
||||||
<BaseContentPlaceholdersText :lines="1" class="w-16 h-5" />
|
<BaseContentPlaceholdersText :lines="1" class="w-16 h-5" />
|
||||||
</BaseContentPlaceholders>
|
</BaseContentPlaceholders>
|
||||||
<label
|
<label
|
||||||
v-else
|
v-else
|
||||||
class="m-0 text-sm font-semibold leading-5 text-gray-400 uppercase"
|
class="m-0 text-sm font-semibold leading-5 text-gray-400 uppercase dark:text-gray-400"
|
||||||
>{{ $t('estimates.total') }} {{ $t('estimates.amount') }}:</label
|
>{{ $t('estimates.total') }} {{ $t('estimates.amount') }}:</label
|
||||||
>
|
>
|
||||||
|
|
||||||
@ -191,7 +219,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, inject, ref, watch } from 'vue'
|
import { computed, inject, ref } from 'vue'
|
||||||
import Guid from 'guid'
|
import Guid from 'guid'
|
||||||
import Tax from './CreateTotalTaxes.vue'
|
import Tax from './CreateTotalTaxes.vue'
|
||||||
import TaxStub from '@/scripts/admin/stub/abilities'
|
import TaxStub from '@/scripts/admin/stub/abilities'
|
||||||
@ -227,20 +255,19 @@ const utils = inject('$utils')
|
|||||||
|
|
||||||
const companyStore = useCompanyStore()
|
const companyStore = useCompanyStore()
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.store[props.storeProp].items,
|
|
||||||
(val) => {
|
|
||||||
setDiscount()
|
|
||||||
}, { deep: true },
|
|
||||||
)
|
|
||||||
|
|
||||||
const totalDiscount = computed({
|
const totalDiscount = computed({
|
||||||
get: () => {
|
get: () => {
|
||||||
return props.store[props.storeProp].discount
|
return props.store[props.storeProp].discount
|
||||||
},
|
},
|
||||||
set: (newValue) => {
|
set: (newValue) => {
|
||||||
|
if (props.store[props.storeProp].discount_type === 'percentage') {
|
||||||
|
props.store[props.storeProp].discount_val = Math.round(
|
||||||
|
(props.store.getSubTotal * newValue) / 100
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
props.store[props.storeProp].discount_val = Math.round(newValue * 100)
|
||||||
|
}
|
||||||
props.store[props.storeProp].discount = newValue
|
props.store[props.storeProp].discount = newValue
|
||||||
setDiscount()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -266,7 +293,7 @@ const itemWiseTaxes = computed(() => {
|
|||||||
} else if (tax.tax_type_id) {
|
} else if (tax.tax_type_id) {
|
||||||
taxes.push({
|
taxes.push({
|
||||||
tax_type_id: tax.tax_type_id,
|
tax_type_id: tax.tax_type_id,
|
||||||
amount: Math.round(tax.amount),
|
amount: tax.amount,
|
||||||
percent: tax.percent,
|
percent: tax.percent,
|
||||||
name: tax.name,
|
name: tax.name,
|
||||||
})
|
})
|
||||||
@ -285,19 +312,6 @@ const defaultCurrency = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function setDiscount() {
|
|
||||||
const newValue = props.store[props.storeProp].discount
|
|
||||||
|
|
||||||
if (props.store[props.storeProp].discount_type === 'percentage') {
|
|
||||||
props.store[props.storeProp].discount_val
|
|
||||||
= Math.round((props.store.getSubTotal * newValue) / 100)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
props.store[props.storeProp].discount_val = Math.round(newValue * 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectFixed() {
|
function selectFixed() {
|
||||||
if (props.store[props.storeProp].discount_type === 'fixed') {
|
if (props.store[props.storeProp].discount_type === 'fixed') {
|
||||||
return
|
return
|
||||||
@ -309,21 +323,24 @@ function selectFixed() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectPercentage() {
|
function selectPercentage() {
|
||||||
if (props.store[props.storeProp].discount_type === 'percentage'){
|
if (props.store[props.storeProp].discount_type === 'percentage') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
props.store[props.storeProp].discount_val =
|
||||||
const val = Math.round(props.store[props.storeProp].discount * 100) / 100
|
(props.store.getSubTotal * props.store[props.storeProp].discount) / 100
|
||||||
|
|
||||||
props.store[props.storeProp].discount_val
|
|
||||||
= Math.round((props.store.getSubTotal * val) / 100)
|
|
||||||
|
|
||||||
props.store[props.storeProp].discount_type = 'percentage'
|
props.store[props.storeProp].discount_type = 'percentage'
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSelectTax(selectedTax) {
|
function onSelectTax(selectedTax) {
|
||||||
let amount = 0
|
let amount = 0
|
||||||
if (props.store.getSubtotalWithDiscount && selectedTax.percent) {
|
|
||||||
|
if (selectedTax.compound_tax && props.store.getSubtotalWithDiscount) {
|
||||||
|
amount = Math.round(
|
||||||
|
((props.store.getSubtotalWithDiscount + props.store.getTotalSimpleTax) *
|
||||||
|
selectedTax.percent) /
|
||||||
|
100
|
||||||
|
)
|
||||||
|
} else if (props.store.getSubtotalWithDiscount && selectedTax.percent) {
|
||||||
amount = Math.round(
|
amount = Math.round(
|
||||||
(props.store.getSubtotalWithDiscount * selectedTax.percent) / 100
|
(props.store.getSubtotalWithDiscount * selectedTax.percent) / 100
|
||||||
)
|
)
|
||||||
@ -334,6 +351,7 @@ function onSelectTax(selectedTax) {
|
|||||||
id: Guid.raw(),
|
id: Guid.raw(),
|
||||||
name: selectedTax.name,
|
name: selectedTax.name,
|
||||||
percent: selectedTax.percent,
|
percent: selectedTax.percent,
|
||||||
|
compound_tax: selectedTax.compound_tax,
|
||||||
tax_type_id: selectedTax.id,
|
tax_type_id: selectedTax.id,
|
||||||
amount,
|
amount,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex items-center justify-between w-full mt-2 text-sm">
|
<div class="flex items-center justify-between w-full mt-2 text-sm">
|
||||||
<label class="font-semibold leading-5 text-gray-500 uppercase">
|
<label class="font-semibold leading-5 text-gray-500 uppercase dark:text-gray-300">
|
||||||
{{ tax.name }} ({{ tax.percent }} %)
|
{{ tax.name }} ({{ tax.percent }} %)
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center justify-center text-lg text-black">
|
<label
|
||||||
|
class="
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
justify-center
|
||||||
|
text-lg
|
||||||
|
text-black
|
||||||
|
dark:text-white
|
||||||
|
"
|
||||||
|
>
|
||||||
<BaseFormatMoney :amount="tax.amount" :currency="currency" />
|
<BaseFormatMoney :amount="tax.amount" :currency="currency" />
|
||||||
|
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="TrashIcon"
|
name="TrashIcon"
|
||||||
class="h-5 ml-2 cursor-pointer"
|
class="h-5 ml-2 cursor-pointer dark:text-red-400"
|
||||||
@click="$emit('remove', tax.id)"
|
@click="$emit('remove', tax.id)"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@ -44,7 +44,7 @@
|
|||||||
>
|
>
|
||||||
<!-- Tax Search Input -->
|
<!-- Tax Search Input -->
|
||||||
|
|
||||||
<div class="relative bg-white">
|
<div class="relative bg-white dark:bg-gray-800">
|
||||||
<div class="relative p-4">
|
<div class="relative p-4">
|
||||||
<BaseInput
|
<BaseInput
|
||||||
v-model="textSearch"
|
v-model="textSearch"
|
||||||
@ -65,13 +65,14 @@
|
|||||||
list
|
list
|
||||||
max-h-36
|
max-h-36
|
||||||
border-t border-gray-200
|
border-t border-gray-200
|
||||||
|
dark:border-gray-600
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(taxType, index) in filteredTaxType"
|
v-for="(taxType, index) in filteredTaxType"
|
||||||
:key="index"
|
:key="index"
|
||||||
:class="{
|
:class="{
|
||||||
'bg-gray-100 cursor-not-allowed opacity-50 pointer-events-none':
|
'bg-gray-100 cursor-not-allowed opacity-50 pointer-events-none dark:bg-gray-900':
|
||||||
taxes.find((val) => {
|
taxes.find((val) => {
|
||||||
return val.tax_type_id === taxType.id
|
return val.tax_type_id === taxType.id
|
||||||
}),
|
}),
|
||||||
@ -84,6 +85,7 @@
|
|||||||
cursor-pointer
|
cursor-pointer
|
||||||
hover:bg-gray-100 hover:cursor-pointer
|
hover:bg-gray-100 hover:cursor-pointer
|
||||||
last:border-b-0
|
last:border-b-0
|
||||||
|
dark:border-gray-600 dark:hover:bg-gray-700/20
|
||||||
"
|
"
|
||||||
@click="selectTaxType(taxType, close)"
|
@click="selectTaxType(taxType, close)"
|
||||||
>
|
>
|
||||||
@ -96,6 +98,7 @@
|
|||||||
leading-tight
|
leading-tight
|
||||||
text-gray-700
|
text-gray-700
|
||||||
cursor-pointer
|
cursor-pointer
|
||||||
|
dark:text-gray-300
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ taxType.name }}
|
{{ taxType.name }}
|
||||||
@ -108,6 +111,7 @@
|
|||||||
font-semibold
|
font-semibold
|
||||||
text-gray-700
|
text-gray-700
|
||||||
cursor-pointer
|
cursor-pointer
|
||||||
|
dark:text-gray-300
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ taxType.percent }} %
|
{{ taxType.percent }} %
|
||||||
@ -138,6 +142,10 @@
|
|||||||
bg-gray-200
|
bg-gray-200
|
||||||
border-none
|
border-none
|
||||||
outline-none
|
outline-none
|
||||||
|
dark:bg-gray-600/70
|
||||||
|
dark:backdrop-blur-xl
|
||||||
|
dark:shadow-glass
|
||||||
|
dark:hover:bg-gray-600/80
|
||||||
"
|
"
|
||||||
@click="openTaxTypeModal"
|
@click="openTaxTypeModal"
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<label class="flex text-gray-800 font-medium text-sm mb-2">
|
<label class="flex text-gray-800 font-medium text-sm mb-2 dark:text-gray-300">
|
||||||
{{ $t('general.select_template') }}
|
{{ $t('general.select_template') }}
|
||||||
<span class="text-sm text-red-500"> *</span>
|
<span class="text-sm text-red-500"> *</span>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@ -57,9 +57,7 @@
|
|||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
</BaseInputGrid>
|
</BaseInputGrid>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3"
|
class="mr-3"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -84,7 +82,7 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ $t('general.create') }}
|
{{ $t('general.create') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -47,15 +47,7 @@
|
|||||||
</BaseInputGrid>
|
</BaseInputGrid>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="
|
|
||||||
z-0
|
|
||||||
flex
|
|
||||||
justify-end
|
|
||||||
p-4
|
|
||||||
border-t border-gray-200 border-solid border-modal-bg
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
type="button"
|
type="button"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -80,7 +72,7 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ categoryStore.isEdit ? $t('general.update') : $t('general.save') }}
|
{{ categoryStore.isEdit ? $t('general.update') : $t('general.save') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -48,6 +48,24 @@
|
|||||||
/>
|
/>
|
||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$tc('settings.company_info.company_slug')"
|
||||||
|
:help-text="$t('settings.company_info.company_slug_help_text')"
|
||||||
|
:error="
|
||||||
|
v$.newCompanyForm.slug.$error &&
|
||||||
|
v$.newCompanyForm.slug.$errors[0].$message
|
||||||
|
"
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model="newCompanyForm.slug"
|
||||||
|
:invalid="v$.newCompanyForm.slug.$error"
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
@input="v$.newCompanyForm.slug.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
<BaseInputGroup
|
<BaseInputGroup
|
||||||
:content-loading="isFetchingInitialData"
|
:content-loading="isFetchingInitialData"
|
||||||
:label="$tc('settings.company_info.country')"
|
:label="$tc('settings.company_info.country')"
|
||||||
@ -98,7 +116,7 @@
|
|||||||
</BaseInputGrid>
|
</BaseInputGrid>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="z-0 flex justify-end p-4 bg-gray-50 border-modal-bg">
|
<BaseModalFooter>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3 text-sm"
|
class="mr-3 text-sm"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -123,14 +141,14 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ $t('general.save') }}
|
{{ $t('general.save') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useModalStore } from '@/scripts/stores/modal'
|
import { useModalStore } from '@/scripts/stores/modal'
|
||||||
import { computed, onMounted, ref, reactive } from 'vue'
|
import { computed, onMounted, ref, reactive, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { required, minLength, helpers } from '@vuelidate/validators'
|
import { required, minLength, helpers } from '@vuelidate/validators'
|
||||||
import { useVuelidate } from '@vuelidate/core'
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
@ -152,6 +170,7 @@ let companyLogoName = ref(null)
|
|||||||
|
|
||||||
const newCompanyForm = reactive({
|
const newCompanyForm = reactive({
|
||||||
name: null,
|
name: null,
|
||||||
|
slug: null,
|
||||||
currency: '',
|
currency: '',
|
||||||
address: {
|
address: {
|
||||||
country_id: null,
|
country_id: null,
|
||||||
@ -162,6 +181,9 @@ const modalActive = computed(() => {
|
|||||||
return modalStore.active && modalStore.componentName === 'CompanyModal'
|
return modalStore.active && modalStore.componentName === 'CompanyModal'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const slugValidator = (value) => {
|
||||||
|
return value == slugify(value)
|
||||||
|
}
|
||||||
const rules = {
|
const rules = {
|
||||||
newCompanyForm: {
|
newCompanyForm: {
|
||||||
name: {
|
name: {
|
||||||
@ -171,6 +193,17 @@ const rules = {
|
|||||||
minLength(3)
|
minLength(3)
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
slug: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
minLength: helpers.withMessage(
|
||||||
|
t('validation.name_min_length', { count: 3 }),
|
||||||
|
minLength(3)
|
||||||
|
),
|
||||||
|
slugValidator: helpers.withMessage(
|
||||||
|
t('validation.invalid_slug'),
|
||||||
|
slugValidator
|
||||||
|
),
|
||||||
|
},
|
||||||
address: {
|
address: {
|
||||||
country_id: {
|
country_id: {
|
||||||
required: helpers.withMessage(t('validation.required'), required),
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
@ -243,6 +276,7 @@ async function submitCompanyData() {
|
|||||||
|
|
||||||
function resetNewCompanyForm() {
|
function resetNewCompanyForm() {
|
||||||
newCompanyForm.name = ''
|
newCompanyForm.name = ''
|
||||||
|
newCompanyForm.slug = ''
|
||||||
newCompanyForm.currency = ''
|
newCompanyForm.currency = ''
|
||||||
newCompanyForm.address.country_id = ''
|
newCompanyForm.address.country_id = ''
|
||||||
|
|
||||||
@ -257,4 +291,24 @@ function closeCompanyModal() {
|
|||||||
v$.value.$reset()
|
v$.value.$reset()
|
||||||
}, 300)
|
}, 300)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// watcher for if change company name then auto fill company slug value
|
||||||
|
watch(
|
||||||
|
() => newCompanyForm.name,
|
||||||
|
(currentValue) => {
|
||||||
|
newCompanyForm.slug = slugify(currentValue)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function slugify(string) {
|
||||||
|
return string
|
||||||
|
.toString()
|
||||||
|
.trim()
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/\s+/g, '-')
|
||||||
|
.replace(/[^\w\-]+/g, '')
|
||||||
|
.replace(/\-\-+/g, '-')
|
||||||
|
.replace(/^-+/, '')
|
||||||
|
.replace(/-+$/, '')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -122,7 +122,7 @@
|
|||||||
<BaseTab :title="$t('customers.portal_access')">
|
<BaseTab :title="$t('customers.portal_access')">
|
||||||
<BaseInputGrid class="col-span-5 lg:col-span-4">
|
<BaseInputGrid class="col-span-5 lg:col-span-4">
|
||||||
<div class="md:col-span-2">
|
<div class="md:col-span-2">
|
||||||
<p class="text-sm text-gray-500">
|
<p class="text-sm text-gray-500 dark:text-gray-300">
|
||||||
{{ $t('customers.portal_access_text') }}
|
{{ $t('customers.portal_access_text') }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -425,9 +425,7 @@
|
|||||||
</BaseTabGroup>
|
</BaseTabGroup>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3 text-sm"
|
class="mr-3 text-sm"
|
||||||
type="button"
|
type="button"
|
||||||
@ -447,7 +445,7 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ $t('general.save') }}
|
{{ $t('general.save') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -38,7 +38,7 @@
|
|||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="z-0 flex justify-end p-4 bg-gray-50 border-modal-bg">
|
<BaseModalFooter>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3 text-sm"
|
class="mr-3 text-sm"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -63,7 +63,7 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -150,9 +150,7 @@
|
|||||||
@Remove="removeUsedSelectedCurrencies"
|
@Remove="removeUsedSelectedCurrencies"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3"
|
class="mr-3"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -179,7 +177,7 @@
|
|||||||
exchangeRateStore.isEdit ? $t('general.update') : $t('general.save')
|
exchangeRateStore.isEdit ? $t('general.update') : $t('general.save')
|
||||||
}}
|
}}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -20,15 +20,7 @@
|
|||||||
@submit="createNewDisk"
|
@submit="createNewDisk"
|
||||||
>
|
>
|
||||||
<template #default="slotProps">
|
<template #default="slotProps">
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="
|
|
||||||
z-0
|
|
||||||
flex
|
|
||||||
justify-end
|
|
||||||
p-4
|
|
||||||
border-t border-solid border-gray-light
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3 text-sm"
|
class="mr-3 text-sm"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -52,7 +44,7 @@
|
|||||||
|
|
||||||
{{ $t('general.save') }}
|
{{ $t('general.save') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</template>
|
</template>
|
||||||
</component>
|
</component>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -89,9 +89,7 @@
|
|||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
</BaseInputGrid>
|
</BaseInputGrid>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3"
|
class="mr-3"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -111,7 +109,7 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ itemStore.isEdit ? $t('general.update') : $t('general.save') }}
|
{{ itemStore.isEdit ? $t('general.update') : $t('general.save') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
|
|||||||
@ -31,15 +31,7 @@
|
|||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="
|
|
||||||
z-0
|
|
||||||
flex
|
|
||||||
justify-end
|
|
||||||
p-4
|
|
||||||
border-t border-gray-200 border-solid border-modal-bg
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
type="button"
|
type="button"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -66,7 +58,7 @@
|
|||||||
itemStore.isItemUnitEdit ? $t('general.update') : $t('general.save')
|
itemStore.isItemUnitEdit ? $t('general.update') : $t('general.save')
|
||||||
}}
|
}}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -62,9 +62,7 @@
|
|||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
</BaseInputGrid>
|
</BaseInputGrid>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
type="button"
|
type="button"
|
||||||
@ -84,7 +82,7 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ $t('general.send') }}
|
{{ $t('general.send') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -63,16 +63,7 @@
|
|||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
</BaseInputGrid>
|
</BaseInputGrid>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="
|
|
||||||
z-0
|
|
||||||
flex
|
|
||||||
justify-end
|
|
||||||
px-4
|
|
||||||
py-4
|
|
||||||
border-t border-solid border-gray-light
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-2"
|
class="mr-2"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -93,7 +84,7 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ noteStore.isEdit ? $t('general.update') : $t('general.save') }}
|
{{ noteStore.isEdit ? $t('general.update') : $t('general.save') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -29,9 +29,7 @@
|
|||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
class="mr-3"
|
class="mr-3"
|
||||||
@ -56,7 +54,7 @@
|
|||||||
: $t('general.save')
|
: $t('general.save')
|
||||||
}}
|
}}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -40,6 +40,7 @@
|
|||||||
px-4
|
px-4
|
||||||
md:px-8
|
md:px-8
|
||||||
py-1.5
|
py-1.5
|
||||||
|
dark:text-gray-200
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ $tc('settings.roles.permission', 2) }}
|
{{ $tc('settings.roles.permission', 2) }}
|
||||||
@ -72,7 +73,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="border-t border-gray-200 py-3">
|
<div class="border-t border-gray-200 dark:border-gray-600 py-3">
|
||||||
<div
|
<div
|
||||||
class="
|
class="
|
||||||
grid grid-cols-1
|
grid grid-cols-1
|
||||||
@ -89,7 +90,7 @@
|
|||||||
:key="gIndex"
|
:key="gIndex"
|
||||||
class="flex flex-col space-y-1"
|
class="flex flex-col space-y-1"
|
||||||
>
|
>
|
||||||
<p class="text-sm text-gray-500 border-b border-gray-200 pb-1 mb-2">
|
<p class="text-sm text-gray-500 dark:text-gray-200 border-b dark:border-gray-600 pb-1 mb-2">
|
||||||
{{ gIndex }}
|
{{ gIndex }}
|
||||||
</p>
|
</p>
|
||||||
<div
|
<div
|
||||||
@ -116,15 +117,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="
|
|
||||||
z-0
|
|
||||||
flex
|
|
||||||
justify-end
|
|
||||||
p-4
|
|
||||||
border-t border-solid border--200 border-modal-bg
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3 text-sm"
|
class="mr-3 text-sm"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -144,7 +137,7 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ !roleStore.isEdit ? $t('general.save') : $t('general.update') }}
|
{{ !roleStore.isEdit ? $t('general.save') : $t('general.update') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -70,7 +70,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid">
|
<BaseModalFooter>
|
||||||
<BaseButton class="mr-3" variant="primary-outline" @click="closeModal">
|
<BaseButton class="mr-3" variant="primary-outline" @click="closeModal">
|
||||||
{{ $t('general.cancel') }}
|
{{ $t('general.cancel') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
@ -80,7 +80,7 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ $t('general.choose') }}
|
{{ $t('general.choose') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -62,9 +62,7 @@
|
|||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
</BaseInputGrid>
|
</BaseInputGrid>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3"
|
class="mr-3"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -85,7 +83,7 @@
|
|||||||
<BaseIcon v-if="!isLoading" name="PhotographIcon" class="h-5 mr-2" />
|
<BaseIcon v-if="!isLoading" name="PhotographIcon" class="h-5 mr-2" />
|
||||||
{{ $t('general.preview') }}
|
{{ $t('general.preview') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div class="my-6 mx-4 border border-gray-200 relative">
|
<div class="my-6 mx-4 border border-gray-200 relative">
|
||||||
@ -106,9 +104,7 @@
|
|||||||
></iframe>
|
></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3"
|
class="mr-3"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -127,7 +123,7 @@
|
|||||||
<BaseIcon v-if="!isLoading" name="PaperAirplaneIcon" class="mr-2" />
|
<BaseIcon v-if="!isLoading" name="PaperAirplaneIcon" class="mr-2" />
|
||||||
{{ $t('general.send') }}
|
{{ $t('general.send') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</div>
|
</div>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -65,9 +65,7 @@
|
|||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
</BaseInputGrid>
|
</BaseInputGrid>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3"
|
class="mr-3"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -93,7 +91,7 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ $t('general.preview') }}
|
{{ $t('general.preview') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div class="my-6 mx-4 border border-gray-200 relative">
|
<div class="my-6 mx-4 border border-gray-200 relative">
|
||||||
@ -114,9 +112,7 @@
|
|||||||
style="min-height: 500px"
|
style="min-height: 500px"
|
||||||
></iframe>
|
></iframe>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3"
|
class="mr-3"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -140,7 +136,7 @@
|
|||||||
/>
|
/>
|
||||||
{{ $t('general.send') }}
|
{{ $t('general.send') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</div>
|
</div>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -65,9 +65,7 @@
|
|||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
</BaseInputGrid>
|
</BaseInputGrid>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3"
|
class="mr-3"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -93,7 +91,7 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ $t('general.preview') }}
|
{{ $t('general.preview') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div class="my-6 mx-4 border border-gray-200 relative">
|
<div class="my-6 mx-4 border border-gray-200 relative">
|
||||||
@ -114,9 +112,7 @@
|
|||||||
style="min-height: 500px"
|
style="min-height: 500px"
|
||||||
></iframe>
|
></iframe>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3"
|
class="mr-3"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -140,7 +136,7 @@
|
|||||||
/>
|
/>
|
||||||
{{ $t('general.send') }}
|
{{ $t('general.send') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</div>
|
</div>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -77,17 +77,20 @@
|
|||||||
@input="v$.currentTaxType.description.$touch()"
|
@input="v$.currentTaxType.description.$touch()"
|
||||||
/>
|
/>
|
||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t('tax_types.compound_tax')"
|
||||||
|
variant="horizontal"
|
||||||
|
class="flex flex-row-reverse"
|
||||||
|
>
|
||||||
|
<BaseSwitch
|
||||||
|
v-model="taxTypeStore.currentTaxType.compound_tax"
|
||||||
|
class="flex items-center"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
</BaseInputGrid>
|
</BaseInputGrid>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="
|
|
||||||
z-0
|
|
||||||
flex
|
|
||||||
justify-end
|
|
||||||
p-4
|
|
||||||
border-t border-solid border--200 border-modal-bg
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3 text-sm"
|
class="mr-3 text-sm"
|
||||||
variant="primary-outline"
|
variant="primary-outline"
|
||||||
@ -111,7 +114,7 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ taxTypeStore.isEdit ? $t('general.update') : $t('general.save') }}
|
{{ taxTypeStore.isEdit ? $t('general.update') : $t('general.save') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
@ -198,7 +201,14 @@ async function submitTaxTypeData() {
|
|||||||
|
|
||||||
function SelectTax(taxData) {
|
function SelectTax(taxData) {
|
||||||
let amount = 0
|
let amount = 0
|
||||||
if (estimateStore.getSubtotalWithDiscount && taxData.percent) {
|
if (taxData.compound_tax && estimateStore.getSubtotalWithDiscount) {
|
||||||
|
amount = Math.round(
|
||||||
|
((estimateStore.getSubtotalWithDiscount +
|
||||||
|
estimateStore.getTotalSimpleTax) *
|
||||||
|
taxData.percent) /
|
||||||
|
100
|
||||||
|
)
|
||||||
|
} else if (estimateStore.getSubtotalWithDiscount && taxData.percent) {
|
||||||
amount = Math.round(
|
amount = Math.round(
|
||||||
(estimateStore.getSubtotalWithDiscount * taxData.percent) / 100
|
(estimateStore.getSubtotalWithDiscount * taxData.percent) / 100
|
||||||
)
|
)
|
||||||
@ -208,6 +218,7 @@ function SelectTax(taxData) {
|
|||||||
id: Guid.raw(),
|
id: Guid.raw(),
|
||||||
name: taxData.name,
|
name: taxData.name,
|
||||||
percent: taxData.percent,
|
percent: taxData.percent,
|
||||||
|
compound_tax: taxData.compound_tax,
|
||||||
tax_type_id: taxData.id,
|
tax_type_id: taxData.id,
|
||||||
amount,
|
amount,
|
||||||
}
|
}
|
||||||
@ -223,6 +234,7 @@ function selectItemTax(taxData) {
|
|||||||
id: Guid.raw(),
|
id: Guid.raw(),
|
||||||
name: taxData.name,
|
name: taxData.name,
|
||||||
percent: taxData.percent,
|
percent: taxData.percent,
|
||||||
|
compound_tax: taxData.compound_tax,
|
||||||
tax_type_id: taxData.id,
|
tax_type_id: taxData.id,
|
||||||
}
|
}
|
||||||
modalStore.refreshData(data)
|
modalStore.refreshData(data)
|
||||||
|
|||||||
@ -87,9 +87,7 @@
|
|||||||
</BaseInputGrid>
|
</BaseInputGrid>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3 text-sm"
|
class="mr-3 text-sm"
|
||||||
type="button"
|
type="button"
|
||||||
@ -109,7 +107,7 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ $t('general.save') }}
|
{{ $t('general.save') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -172,15 +172,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<BaseModalFooter>
|
||||||
class="
|
|
||||||
z-0
|
|
||||||
flex
|
|
||||||
justify-end
|
|
||||||
p-4
|
|
||||||
border-t border-solid border-gray-light border-modal-bg
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="mr-3"
|
class="mr-3"
|
||||||
type="button"
|
type="button"
|
||||||
@ -207,7 +199,7 @@
|
|||||||
!customFieldStore.isEdit ? $t('general.save') : $t('general.update')
|
!customFieldStore.isEdit ? $t('general.save') : $t('general.update')
|
||||||
}}
|
}}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</BaseModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -153,7 +153,7 @@
|
|||||||
<BaseSwitch v-model="set_as_default" class="flex" />
|
<BaseSwitch v-model="set_as_default" class="flex" />
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-4 right">
|
<div class="ml-4 right">
|
||||||
<p class="p-0 mb-1 text-base leading-snug text-black box-title">
|
<p class="p-0 mb-1 text-base leading-snug text-black dark:text-white box-title">
|
||||||
{{ $t('settings.disk.is_default') }}
|
{{ $t('settings.disk.is_default') }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -132,7 +132,7 @@
|
|||||||
<BaseSwitch v-model="set_as_default" class="flex" />
|
<BaseSwitch v-model="set_as_default" class="flex" />
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-4 right">
|
<div class="ml-4 right">
|
||||||
<p class="p-0 mb-1 text-base leading-snug text-black box-title">
|
<p class="p-0 mb-1 text-base leading-snug text-black dark:text-white box-title">
|
||||||
{{ $t('settings.disk.is_default') }}
|
{{ $t('settings.disk.is_default') }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -63,7 +63,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ml-4 right">
|
<div class="ml-4 right">
|
||||||
<p class="p-0 mb-1 text-base leading-snug text-black box-title">
|
<p class="p-0 mb-1 text-base leading-snug text-black dark:text-white box-title">
|
||||||
{{ $t('settings.disk.is_default') }}
|
{{ $t('settings.disk.is_default') }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -134,7 +134,7 @@
|
|||||||
<BaseSwitch v-model="set_as_default" class="flex" />
|
<BaseSwitch v-model="set_as_default" class="flex" />
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-4 right">
|
<div class="ml-4 right">
|
||||||
<p class="p-0 mb-1 text-base leading-snug text-black box-title">
|
<p class="p-0 mb-1 text-base leading-snug text-black dark:text-white box-title">
|
||||||
{{ $t('settings.disk.is_default') }}
|
{{ $t('settings.disk.is_default') }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="h-screen overflow-y-auto text-base">
|
<div class="h-screen overflow-y-auto text-base dark:bg-gray-800/80 dark:text-white">
|
||||||
<NotificationRoot />
|
<NotificationRoot />
|
||||||
|
|
||||||
<div class="container mx-auto px-4">
|
<div class="container px-4 mx-auto">
|
||||||
<router-view />
|
<router-view />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="grid h-screen grid-cols-12 overflow-y-hidden bg-gray-100">
|
<div class="grid h-screen grid-cols-12 overflow-y-hidden bg-gray-100 dark:bg-gray-900">
|
||||||
<NotificationRoot />
|
<NotificationRoot />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -15,8 +15,17 @@
|
|||||||
bg-gradient-to-r
|
bg-gradient-to-r
|
||||||
from-primary-500
|
from-primary-500
|
||||||
to-primary-400
|
to-primary-400
|
||||||
|
dark:from-gray-700/70 dark:to-gray-800/70
|
||||||
|
bg-primary-500
|
||||||
|
dark:bg-transparent
|
||||||
|
dark:backdrop-blur-xl
|
||||||
|
dark:shadow-glass
|
||||||
|
dark:border
|
||||||
|
dark:border-white/10
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
<BaseDarkHighlight />
|
||||||
|
|
||||||
<router-link
|
<router-link
|
||||||
to="/admin/dashboard"
|
to="/admin/dashboard"
|
||||||
class="
|
class="
|
||||||
@ -53,6 +62,7 @@
|
|||||||
cursor-pointer
|
cursor-pointer
|
||||||
md:hidden md:ml-0
|
md:hidden md:ml-0
|
||||||
hover:bg-gray-100
|
hover:bg-gray-100
|
||||||
|
dark:bg-gray-800 dark:border-gray-500 dark:border
|
||||||
"
|
"
|
||||||
@click.prevent="onToggle"
|
@click.prevent="onToggle"
|
||||||
>
|
>
|
||||||
@ -64,7 +74,7 @@
|
|||||||
v-if="hasCreateAbilities"
|
v-if="hasCreateAbilities"
|
||||||
class="relative hidden float-left m-0 md:block"
|
class="relative hidden float-left m-0 md:block"
|
||||||
>
|
>
|
||||||
<BaseDropdown width-class="w-48">
|
<BaseDropdown width-class="w-48" >
|
||||||
<template #activator>
|
<template #activator>
|
||||||
<div
|
<div
|
||||||
class="
|
class="
|
||||||
@ -78,19 +88,21 @@
|
|||||||
bg-white
|
bg-white
|
||||||
rounded
|
rounded
|
||||||
md:h-9 md:w-9
|
md:h-9 md:w-9
|
||||||
|
dark:bg-gray-700 dark:border-gray-500 dark:border
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<BaseIcon name="PlusIcon" class="w-5 h-5 text-gray-600" />
|
<BaseIcon name="PlusIcon" class="w-5 h-5 text-gray-600 dark:text-white" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<router-link to="/admin/invoices/create">
|
<router-link to="/admin/invoices/create">
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.CREATE_INVOICE)"
|
v-if="userStore.hasAbilities(abilities.CREATE_INVOICE)"
|
||||||
|
v-slot="slotProps"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="DocumentTextIcon"
|
name="DocumentTextIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
{{ $t('invoices.new_invoice') }}
|
{{ $t('invoices.new_invoice') }}
|
||||||
@ -99,10 +111,11 @@
|
|||||||
<router-link to="/admin/estimates/create">
|
<router-link to="/admin/estimates/create">
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.CREATE_ESTIMATE)"
|
v-if="userStore.hasAbilities(abilities.CREATE_ESTIMATE)"
|
||||||
|
v-slot="slotProps"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="DocumentIcon"
|
name="DocumentIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
{{ $t('estimates.new_estimate') }}
|
{{ $t('estimates.new_estimate') }}
|
||||||
@ -112,10 +125,11 @@
|
|||||||
<router-link to="/admin/customers/create">
|
<router-link to="/admin/customers/create">
|
||||||
<BaseDropdownItem
|
<BaseDropdownItem
|
||||||
v-if="userStore.hasAbilities(abilities.CREATE_CUSTOMER)"
|
v-if="userStore.hasAbilities(abilities.CREATE_CUSTOMER)"
|
||||||
|
v-slot="slotProps"
|
||||||
>
|
>
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="UserIcon"
|
name="UserIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
{{ $t('customers.new_customer') }}
|
{{ $t('customers.new_customer') }}
|
||||||
@ -148,20 +162,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<router-link to="/admin/settings/account-settings">
|
<router-link to="/admin/settings/account-settings">
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="CogIcon"
|
name="CogIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
{{ $t('navigation.settings') }}
|
{{ $t('navigation.settings') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<BaseDropdownItem @click="logout">
|
<BaseDropdownItem v-slot="slotProps" @click="logout">
|
||||||
<BaseIcon
|
<BaseIcon
|
||||||
name="LogoutIcon"
|
name="LogoutIcon"
|
||||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
:class="slotProps.class"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
{{ $t('navigation.logout') }}
|
{{ $t('navigation.logout') }}
|
||||||
|
|||||||
@ -15,7 +15,9 @@
|
|||||||
leave-from="opacity-100"
|
leave-from="opacity-100"
|
||||||
leave-to="opacity-0"
|
leave-to="opacity-0"
|
||||||
>
|
>
|
||||||
<DialogOverlay class="fixed inset-0 bg-gray-600 bg-opacity-75" />
|
<DialogOverlay
|
||||||
|
class="fixed inset-0 bg-gray-600 bg-opacity-75 dark:bg-gray-900/90"
|
||||||
|
/>
|
||||||
</TransitionChild>
|
</TransitionChild>
|
||||||
|
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
@ -27,7 +29,9 @@
|
|||||||
leave-from="translate-x-0"
|
leave-from="translate-x-0"
|
||||||
leave-to="-translate-x-full"
|
leave-to="-translate-x-full"
|
||||||
>
|
>
|
||||||
<div class="relative flex flex-col flex-1 w-full max-w-xs bg-white">
|
<div
|
||||||
|
class="relative flex flex-col flex-1 w-full max-w-xs bg-white dark:bg-gray-800"
|
||||||
|
>
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as="template"
|
as="template"
|
||||||
enter="ease-in-out duration-300"
|
enter="ease-in-out duration-300"
|
||||||
@ -40,18 +44,17 @@
|
|||||||
<div class="absolute top-0 right-0 pt-2 -mr-12">
|
<div class="absolute top-0 right-0 pt-2 -mr-12">
|
||||||
<button
|
<button
|
||||||
class="
|
class="
|
||||||
flex
|
flex
|
||||||
items-center
|
items-center
|
||||||
justify-center
|
justify-center
|
||||||
w-10
|
w-10
|
||||||
h-10
|
h-10
|
||||||
ml-1
|
ml-1
|
||||||
rounded-full
|
rounded-full
|
||||||
focus:outline-none
|
focus:outline-none
|
||||||
focus:ring-2
|
focus:ring-2
|
||||||
focus:ring-inset
|
focus:ring-inset
|
||||||
focus:ring-white
|
focus:ring-white"
|
||||||
"
|
|
||||||
@click="globalStore.setSidebarVisibility(false)"
|
@click="globalStore.setSidebarVisibility(false)"
|
||||||
>
|
>
|
||||||
<span class="sr-only">Close sidebar</span>
|
<span class="sr-only">Close sidebar</span>
|
||||||
@ -65,10 +68,8 @@
|
|||||||
</TransitionChild>
|
</TransitionChild>
|
||||||
<div class="flex-1 h-0 pt-5 pb-4 overflow-y-auto">
|
<div class="flex-1 h-0 pt-5 pb-4 overflow-y-auto">
|
||||||
<div class="flex items-center shrink-0 px-4 mb-10">
|
<div class="flex items-center shrink-0 px-4 mb-10">
|
||||||
<MainLogo
|
<img class="h-auto max-w-full w-36 hidden dark:block" :src="getDarkLogo"/>
|
||||||
class="block h-auto max-w-full w-36 text-primary-400"
|
<img class="h-auto max-w-full w-36 block dark:hidden" :src="getLightLogo"/>
|
||||||
alt="Crater Logo"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav
|
<nav
|
||||||
@ -82,8 +83,8 @@
|
|||||||
:to="item.link"
|
:to="item.link"
|
||||||
:class="[
|
:class="[
|
||||||
hasActiveUrl(item.link)
|
hasActiveUrl(item.link)
|
||||||
? 'text-primary-500 border-primary-500 bg-gray-100 '
|
? 'text-primary-500 border-primary-500 bg-gray-100 dark:shadow-glass dark:backdrop-blur-xl dark:hover:bg-gray-700 dark:bg-gray-700/50 dark:text-primary-400 dark:font-medium'
|
||||||
: 'text-black',
|
: 'text-black dark:text-gray-300',
|
||||||
'cursor-pointer px-0 pl-4 py-3 border-transparent flex items-center border-l-4 border-solid text-sm not-italic font-medium',
|
'cursor-pointer px-0 pl-4 py-3 border-transparent flex items-center border-l-4 border-solid text-sm not-italic font-medium',
|
||||||
]"
|
]"
|
||||||
@click="globalStore.setSidebarVisibility(false)"
|
@click="globalStore.setSidebarVisibility(false)"
|
||||||
@ -92,7 +93,7 @@
|
|||||||
:name="item.icon"
|
:name="item.icon"
|
||||||
:class="[
|
:class="[
|
||||||
hasActiveUrl(item.link)
|
hasActiveUrl(item.link)
|
||||||
? 'text-primary-500 '
|
? 'text-primary-500 dark:text-primary-400'
|
||||||
: 'text-gray-400',
|
: 'text-gray-400',
|
||||||
'mr-4 shrink-0 h-5 w-5',
|
'mr-4 shrink-0 h-5 w-5',
|
||||||
]"
|
]"
|
||||||
@ -100,6 +101,10 @@
|
|||||||
/>
|
/>
|
||||||
{{ $t(item.title) }}
|
{{ $t(item.title) }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
<LightDarkSwitch
|
||||||
|
:show-label="false"
|
||||||
|
class="absolute right-6 top-6 !w-auto"
|
||||||
|
/>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -113,17 +118,16 @@
|
|||||||
<!-- DESKTOP MENU -->
|
<!-- DESKTOP MENU -->
|
||||||
<div
|
<div
|
||||||
class="
|
class="
|
||||||
hidden
|
hidden
|
||||||
w-56
|
w-56
|
||||||
h-screen
|
h-screen
|
||||||
pb-32
|
bg-white
|
||||||
overflow-y-auto
|
border-r border-gray-200 border-solid
|
||||||
bg-white
|
xl:w-64
|
||||||
border-r border-gray-200 border-solid
|
md:fixed md:flex md:flex-col md:inset-y-0
|
||||||
xl:w-64
|
pt-16
|
||||||
md:fixed md:flex md:flex-col md:inset-y-0
|
dark:border-gray-800
|
||||||
pt-16
|
dark:bg-gray-800/80"
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="menu in globalStore.menuGroups"
|
v-for="menu in globalStore.menuGroups"
|
||||||
@ -136,8 +140,8 @@
|
|||||||
:to="item.link"
|
:to="item.link"
|
||||||
:class="[
|
:class="[
|
||||||
hasActiveUrl(item.link)
|
hasActiveUrl(item.link)
|
||||||
? 'text-primary-500 border-primary-500 bg-gray-100 '
|
? 'text-primary-500 border-primary-500 bg-gray-100 dark:border-primary-400 dark:shadow-glass dark:backdrop-blur-xl dark:hover:bg-gray-700 dark:bg-gray-700/50 dark:text-primary-400 dark:font-medium'
|
||||||
: 'text-black',
|
: 'text-black dark:hover:bg-transparent dark:hover:text-white dark:text-gray-300',
|
||||||
'cursor-pointer px-0 pl-6 hover:bg-gray-50 py-3 group flex items-center border-l-4 border-solid border-transparent text-sm not-italic font-medium',
|
'cursor-pointer px-0 pl-6 hover:bg-gray-50 py-3 group flex items-center border-l-4 border-solid border-transparent text-sm not-italic font-medium',
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
@ -145,8 +149,8 @@
|
|||||||
:name="item.icon"
|
:name="item.icon"
|
||||||
:class="[
|
:class="[
|
||||||
hasActiveUrl(item.link)
|
hasActiveUrl(item.link)
|
||||||
? 'text-primary-500 group-hover:text-primary-500 '
|
? 'text-primary-500 dark:text-primary-400'
|
||||||
: 'text-gray-400 group-hover:text-black',
|
: 'text-gray-400 group-hover:text-black dark:text-gray-400 dark:group-hover:text-white',
|
||||||
'mr-4 shrink-0 h-5 w-5 ',
|
'mr-4 shrink-0 h-5 w-5 ',
|
||||||
]"
|
]"
|
||||||
/>
|
/>
|
||||||
@ -154,12 +158,14 @@
|
|||||||
{{ $t(item.title) }}
|
{{ $t(item.title) }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
<LightDarkSwitch
|
||||||
|
class="absolute bottom-0 py-4 border-t border-gray-200 dark:border-gray-700"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import MainLogo from '@/scripts/components/icons/MainLogo.vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogOverlay,
|
DialogOverlay,
|
||||||
@ -169,10 +175,14 @@ import {
|
|||||||
|
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||||
|
import LightDarkSwitch from '@/scripts/components/LightDarkSwitcher.vue'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const globalStore = useGlobalStore()
|
const globalStore = useGlobalStore()
|
||||||
|
|
||||||
|
const getDarkLogo = computed(() => new URL('/img/logo-white.png', import.meta.url))
|
||||||
|
const getLightLogo = computed(() => new URL('/img/crater-logo.png', import.meta.url))
|
||||||
|
|
||||||
function hasActiveUrl(url) {
|
function hasActiveUrl(url) {
|
||||||
return route.path.indexOf(url) > -1
|
return route.path.indexOf(url) > -1
|
||||||
}
|
}
|
||||||
|
|||||||
@ -184,6 +184,20 @@ export const useCompanyStore = (useWindow = false) => {
|
|||||||
setDefaultCurrency(data) {
|
setDefaultCurrency(data) {
|
||||||
this.defaultCurrency = data.currency
|
this.defaultCurrency = data.currency
|
||||||
},
|
},
|
||||||
|
|
||||||
|
checkCompanyHasCurrencyTransactions() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axios
|
||||||
|
.get(`/api/v1/company/has-transactions`)
|
||||||
|
.then((response) => {
|
||||||
|
resolve(response)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
handleError(err)
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})()
|
})()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -143,8 +143,7 @@ export const useEstimateStore = (useWindow = false) => {
|
|||||||
axios
|
axios
|
||||||
.get(`/api/v1/estimates/${id}`)
|
.get(`/api/v1/estimates/${id}`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.setEstimateData(response.data.data)
|
Object.assign(this.newEstimate, response.data.data)
|
||||||
this.setCustomerAddresses(this.newEstimate.customer)
|
|
||||||
resolve(response)
|
resolve(response)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@ -155,41 +154,6 @@ export const useEstimateStore = (useWindow = false) => {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
setEstimateData(estimate) {
|
|
||||||
Object.assign(this.newEstimate, estimate)
|
|
||||||
if (this.newEstimate.tax_per_item === 'YES') {
|
|
||||||
this.newEstimate.items.forEach((_i) => {
|
|
||||||
if (_i.taxes && !_i.taxes.length){
|
|
||||||
_i.taxes.push({ ...taxStub, id: Guid.raw() })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (this.newEstimate.discount_per_item === 'YES') {
|
|
||||||
this.newEstimate.items.forEach((_i, index) => {
|
|
||||||
if (_i.discount_type === 'fixed'){
|
|
||||||
this.newEstimate.items[index].discount = _i.discount / 100
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (this.newEstimate.discount_type === 'fixed'){
|
|
||||||
this.newEstimate.discount = this.newEstimate.discount / 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setCustomerAddresses(customer) {
|
|
||||||
const customer_business = customer.customer_business
|
|
||||||
|
|
||||||
if (customer_business?.billing_address){
|
|
||||||
this.newEstimate.customer.billing_address = customer_business.billing_address
|
|
||||||
}
|
|
||||||
|
|
||||||
if (customer_business?.shipping_address){
|
|
||||||
this.newEstimate.customer.shipping_address = customer_business.shipping_address
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
addSalesTaxUs() {
|
addSalesTaxUs() {
|
||||||
const taxTypeStore = useTaxTypeStore()
|
const taxTypeStore = useTaxTypeStore()
|
||||||
let salesTax = { ...taxStub }
|
let salesTax = { ...taxStub }
|
||||||
|
|||||||
@ -34,7 +34,7 @@ export const useGlobalStore = (useWindow = false) => {
|
|||||||
isAppLoaded: false,
|
isAppLoaded: false,
|
||||||
isSidebarOpen: false,
|
isSidebarOpen: false,
|
||||||
areCurrenciesLoading: false,
|
areCurrenciesLoading: false,
|
||||||
|
isDarkModeOn: localStorage.getItem('theme') === 'dark' || document.documentElement.classList.contains('dark'),
|
||||||
downloadReport: null,
|
downloadReport: null,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
@ -70,8 +70,8 @@ export const useGlobalStore = (useWindow = false) => {
|
|||||||
moduleStore.apiToken = response.data.global_settings.api_token
|
moduleStore.apiToken = response.data.global_settings.api_token
|
||||||
moduleStore.enableModules = response.data.modules
|
moduleStore.enableModules = response.data.modules
|
||||||
|
|
||||||
// company store
|
// company store
|
||||||
companyStore.companies = response.data.companies
|
companyStore.companies = response.data.companies
|
||||||
companyStore.selectedCompany = response.data.current_company
|
companyStore.selectedCompany = response.data.current_company
|
||||||
companyStore.setSelectedCompany(response.data.current_company)
|
companyStore.setSelectedCompany(response.data.current_company)
|
||||||
companyStore.selectedCompanySettings =
|
companyStore.selectedCompanySettings =
|
||||||
|
|||||||
@ -133,8 +133,8 @@ export const useInvoiceStore = (useWindow = false) => {
|
|||||||
axios
|
axios
|
||||||
.get(`/api/v1/invoices/${id}`)
|
.get(`/api/v1/invoices/${id}`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.setInvoiceData(response.data.data)
|
Object.assign(this.newInvoice, response.data.data)
|
||||||
this.setCustomerAddresses(this.newInvoice.customer)
|
this.newInvoice.customer = response.data.data.customer
|
||||||
resolve(response)
|
resolve(response)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@ -144,38 +144,6 @@ export const useInvoiceStore = (useWindow = false) => {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
setInvoiceData(invoice) {
|
|
||||||
Object.assign(this.newInvoice, invoice)
|
|
||||||
|
|
||||||
if (this.newInvoice.tax_per_item === 'YES') {
|
|
||||||
this.newInvoice.items.forEach((_i) => {
|
|
||||||
if (_i.taxes && !_i.taxes.length)
|
|
||||||
_i.taxes.push({ ...taxStub, id: Guid.raw() })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.newInvoice.discount_per_item === 'YES') {
|
|
||||||
this.newInvoice.items.forEach((_i, index) => {
|
|
||||||
if (_i.discount_type === 'fixed')
|
|
||||||
this.newInvoice.items[index].discount = _i.discount / 100
|
|
||||||
})
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (this.newInvoice.discount_type === 'fixed')
|
|
||||||
this.newInvoice.discount = this.newInvoice.discount / 100
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setCustomerAddresses(customer) {
|
|
||||||
const customer_business = customer.customer_business
|
|
||||||
|
|
||||||
if (customer_business?.billing_address)
|
|
||||||
this.newInvoice.customer.billing_address = customer_business.billing_address
|
|
||||||
|
|
||||||
if (customer_business?.shipping_address)
|
|
||||||
this.newInvoice.customer.shipping_address = customer_business.shipping_address
|
|
||||||
},
|
|
||||||
|
|
||||||
addSalesTaxUs() {
|
addSalesTaxUs() {
|
||||||
const taxTypeStore = useTaxTypeStore()
|
const taxTypeStore = useTaxTypeStore()
|
||||||
let salesTax = { ...taxStub }
|
let salesTax = { ...taxStub }
|
||||||
|
|||||||
@ -32,7 +32,7 @@
|
|||||||
<div class="mt-4 mb-4 text-sm">
|
<div class="mt-4 mb-4 text-sm">
|
||||||
<router-link
|
<router-link
|
||||||
to="/login"
|
to="/login"
|
||||||
class="text-sm text-primary-400 hover:text-gray-700"
|
class="text-sm text-primary-400 hover:text-gray-700 dark:hover:text-primary-500"
|
||||||
>
|
>
|
||||||
{{ $t('general.back_to_login') }}
|
{{ $t('general.back_to_login') }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|||||||
@ -49,7 +49,7 @@
|
|||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<router-link
|
<router-link
|
||||||
to="forgot-password"
|
to="forgot-password"
|
||||||
class="text-sm text-primary-400 hover:text-gray-700"
|
class="text-sm text-primary-400 hover:text-gray-700 dark:hover:text-primary-500"
|
||||||
>
|
>
|
||||||
{{ $t('login.forgot_password') }}
|
{{ $t('login.forgot_password') }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|||||||
@ -171,7 +171,7 @@
|
|||||||
|
|
||||||
<BaseInputGrid class="col-span-5 lg:col-span-4">
|
<BaseInputGrid class="col-span-5 lg:col-span-4">
|
||||||
<div class="md:col-span-2">
|
<div class="md:col-span-2">
|
||||||
<p class="text-sm text-gray-500">
|
<p class="text-sm text-gray-500 dark:text-gray-300">
|
||||||
{{ $t('customers.portal_access_text') }}
|
{{ $t('customers.portal_access_text') }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@ -113,7 +113,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<BaseDropdownItem @click="removeMultipleCustomers">
|
<BaseDropdownItem @click="removeMultipleCustomers">
|
||||||
<BaseIcon name="TrashIcon" class="mr-3 text-gray-600" />
|
<BaseIcon name="TrashIcon" class="mr-3 text-gray-600 dark:text-gray-400 dark:group-hover:text-white" />
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</BaseDropdown>
|
</BaseDropdown>
|
||||||
@ -154,7 +154,7 @@
|
|||||||
:text="row.data.name"
|
:text="row.data.name"
|
||||||
:length="30"
|
:length="30"
|
||||||
tag="span"
|
tag="span"
|
||||||
class="font-medium text-primary-500 flex flex-col"
|
class="font-medium text-primary-500 flex flex-col dark:text-primary-400"
|
||||||
/>
|
/>
|
||||||
<BaseText
|
<BaseText
|
||||||
:text="row.data.contact_name ? row.data.contact_name : ''"
|
:text="row.data.contact_name ? row.data.contact_name : ''"
|
||||||
|
|||||||
@ -34,8 +34,8 @@
|
|||||||
v-if="userStore.hasAbilities(abilities.CREATE_ESTIMATE)"
|
v-if="userStore.hasAbilities(abilities.CREATE_ESTIMATE)"
|
||||||
:to="`/admin/estimates/create?customer=${$route.params.id}`"
|
:to="`/admin/estimates/create?customer=${$route.params.id}`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem class="">
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon name="DocumentIcon" class="mr-3 text-gray-600" />
|
<BaseIcon name="DocumentIcon" :class="slotProps.class" />
|
||||||
{{ $t('estimates.new_estimate') }}
|
{{ $t('estimates.new_estimate') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</router-link>
|
</router-link>
|
||||||
@ -44,8 +44,8 @@
|
|||||||
v-if="userStore.hasAbilities(abilities.CREATE_INVOICE)"
|
v-if="userStore.hasAbilities(abilities.CREATE_INVOICE)"
|
||||||
:to="`/admin/invoices/create?customer=${$route.params.id}`"
|
:to="`/admin/invoices/create?customer=${$route.params.id}`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon name="DocumentTextIcon" class="mr-3 text-gray-600" />
|
<BaseIcon name="DocumentTextIcon" :class="slotProps.class" />
|
||||||
{{ $t('invoices.new_invoice') }}
|
{{ $t('invoices.new_invoice') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</router-link>
|
</router-link>
|
||||||
@ -54,8 +54,8 @@
|
|||||||
v-if="userStore.hasAbilities(abilities.CREATE_PAYMENT)"
|
v-if="userStore.hasAbilities(abilities.CREATE_PAYMENT)"
|
||||||
:to="`/admin/payments/create?customer=${$route.params.id}`"
|
:to="`/admin/payments/create?customer=${$route.params.id}`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon name="CreditCardIcon" class="mr-3 text-gray-600" />
|
<BaseIcon name="CreditCardIcon" :class="slotProps.class" />
|
||||||
{{ $t('payments.new_payment') }}
|
{{ $t('payments.new_payment') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</router-link>
|
</router-link>
|
||||||
@ -64,8 +64,8 @@
|
|||||||
v-if="userStore.hasAbilities(abilities.CREATE_EXPENSE)"
|
v-if="userStore.hasAbilities(abilities.CREATE_EXPENSE)"
|
||||||
:to="`/admin/expenses/create?customer=${$route.params.id}`"
|
:to="`/admin/expenses/create?customer=${$route.params.id}`"
|
||||||
>
|
>
|
||||||
<BaseDropdownItem>
|
<BaseDropdownItem v-slot="slotProps">
|
||||||
<BaseIcon name="CalculatorIcon" class="mr-3 text-gray-600" />
|
<BaseIcon name="CalculatorIcon" :class="slotProps.class" />
|
||||||
{{ $t('expenses.new_expense') }}
|
{{ $t('expenses.new_expense') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pt-6 mt-5 border-t border-solid lg:pt-8 md:pt-4 border-gray-200">
|
<div class="pt-6 mt-5 border-t border-solid lg:pt-8 md:pt-4 border-gray-200 dark:border-gray-600">
|
||||||
<!-- Basic Info -->
|
<!-- Basic Info -->
|
||||||
<BaseHeading>
|
<BaseHeading>
|
||||||
{{ $t('customers.basic_info') }}
|
{{ $t('customers.basic_info') }}
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
xl:ml-64
|
xl:ml-64
|
||||||
w-88
|
w-88
|
||||||
xl:block
|
xl:block
|
||||||
|
dark:bg-gray-800
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -25,6 +26,7 @@
|
|||||||
pb-2
|
pb-2
|
||||||
border border-gray-200 border-solid
|
border border-gray-200 border-solid
|
||||||
height-full
|
height-full
|
||||||
|
dark:border-gray-600
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<BaseInput
|
<BaseInput
|
||||||
@ -59,6 +61,7 @@
|
|||||||
mb-2
|
mb-2
|
||||||
text-sm
|
text-sm
|
||||||
border-b border-gray-200 border-solid
|
border-b border-gray-200 border-solid
|
||||||
|
dark:border-gray-600
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ $t('general.sort_by') }}
|
{{ $t('general.sort_by') }}
|
||||||
@ -114,6 +117,7 @@
|
|||||||
border-l border-gray-200 border-solid
|
border-l border-gray-200 border-solid
|
||||||
sidebar
|
sidebar
|
||||||
base-scroll
|
base-scroll
|
||||||
|
dark:border-gray-600
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div v-for="(customer, index) in customerList" :key="index">
|
<div v-for="(customer, index) in customerList" :key="index">
|
||||||
@ -122,9 +126,9 @@
|
|||||||
:id="'customer-' + customer.id"
|
:id="'customer-' + customer.id"
|
||||||
:to="`/admin/customers/${customer.id}/view`"
|
:to="`/admin/customers/${customer.id}/view`"
|
||||||
:class="[
|
:class="[
|
||||||
'flex justify-between p-4 items-center cursor-pointer hover:bg-gray-100 border-l-4 border-transparent',
|
'flex justify-between p-4 items-center cursor-pointer hover:bg-gray-100 border-l-4 border-transparent dark:hover:bg-gray-700',
|
||||||
{
|
{
|
||||||
'bg-gray-100 border-l-4 border-primary-500 border-solid':
|
'bg-gray-100 border-l-4 border-primary-500 border-solid dark:border-primary-400 dark:bg-gray-700':
|
||||||
hasActiveUrl(customer.id),
|
hasActiveUrl(customer.id),
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
@ -143,6 +147,7 @@
|
|||||||
text-black
|
text-black
|
||||||
capitalize
|
capitalize
|
||||||
truncate
|
truncate
|
||||||
|
dark:text-white
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -157,6 +162,7 @@
|
|||||||
font-medium
|
font-medium
|
||||||
leading-5
|
leading-5
|
||||||
text-gray-600
|
text-gray-600
|
||||||
|
dark:text-gray-400
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -175,7 +181,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<p
|
<p
|
||||||
v-if="!customerList?.length && !isFetching"
|
v-if="!customerList?.length && !isFetching"
|
||||||
class="flex justify-center px-4 mt-5 text-sm text-gray-600"
|
class="flex justify-center px-4 mt-5 text-sm text-gray-600 dark:text-gray-300"
|
||||||
>
|
>
|
||||||
{{ $t('customers.no_matching_customers') }}
|
{{ $t('customers.no_matching_customers') }}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@ -2,8 +2,23 @@
|
|||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
v-if="dashboardStore.isDashboardDataLoaded"
|
v-if="dashboardStore.isDashboardDataLoaded"
|
||||||
class="grid grid-cols-10 mt-8 bg-white rounded shadow"
|
class="
|
||||||
|
grid
|
||||||
|
grid-cols-10
|
||||||
|
mt-8
|
||||||
|
bg-white
|
||||||
|
rounded shadow
|
||||||
|
dark:text-white
|
||||||
|
dark:backdrop-blur-xl
|
||||||
|
dark:shadow-glass
|
||||||
|
dark:border
|
||||||
|
dark:bg-opacity-70
|
||||||
|
dark:border-white/10
|
||||||
|
dark:bg-gray-800
|
||||||
|
relative
|
||||||
|
"
|
||||||
>
|
>
|
||||||
|
<BaseDarkHighlight />
|
||||||
<!-- Chart -->
|
<!-- Chart -->
|
||||||
<div
|
<div
|
||||||
class="
|
class="
|
||||||
@ -54,6 +69,7 @@
|
|||||||
lg:border-t-0 lg:text-right lg:col-span-3
|
lg:border-t-0 lg:text-right lg:col-span-3
|
||||||
xl:col-span-2
|
xl:col-span-2
|
||||||
lg:grid-cols-1
|
lg:grid-cols-1
|
||||||
|
dark:border-white/10
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
@ -96,15 +112,7 @@
|
|||||||
</span>
|
</span>
|
||||||
<br />
|
<br />
|
||||||
<span
|
<span
|
||||||
class="
|
class="block mt-1 text-xl font-semibold leading-8 lg:text-2xl text-red-400"
|
||||||
block
|
|
||||||
mt-1
|
|
||||||
text-xl
|
|
||||||
font-semibold
|
|
||||||
leading-8
|
|
||||||
lg:text-2xl
|
|
||||||
text-red-400
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<BaseFormatMoney
|
<BaseFormatMoney
|
||||||
:amount="dashboardStore.totalExpenses"
|
:amount="dashboardStore.totalExpenses"
|
||||||
@ -116,8 +124,10 @@
|
|||||||
class="
|
class="
|
||||||
col-span-3
|
col-span-3
|
||||||
p-6
|
p-6
|
||||||
border-t border-gray-200 border-solid
|
border-t
|
||||||
|
border-gray-200 border-solid
|
||||||
lg:col-span-1
|
lg:col-span-1
|
||||||
|
dark:border-white/10
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<span class="text-xs leading-5 lg:text-sm">
|
<span class="text-xs leading-5 lg:text-sm">
|
||||||
@ -132,7 +142,7 @@
|
|||||||
font-semibold
|
font-semibold
|
||||||
leading-8
|
leading-8
|
||||||
lg:text-2xl
|
lg:text-2xl
|
||||||
text-primary-500
|
text-primary-500 dark:text-primary-400
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<BaseFormatMoney
|
<BaseFormatMoney
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<BaseContentPlaceholders
|
<BaseContentPlaceholders
|
||||||
class="grid grid-cols-10 mt-8 bg-white rounded shadow"
|
class="grid grid-cols-10 mt-8 bg-white rounded shadow dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<!-- Chart -->
|
<!-- Chart -->
|
||||||
<div
|
<div
|
||||||
@ -29,6 +29,7 @@
|
|||||||
text-center
|
text-center
|
||||||
border-t border-l border-gray-200 border-solid
|
border-t border-l border-gray-200 border-solid
|
||||||
lg:border-t-0 lg:text-right lg:col-span-3
|
lg:border-t-0 lg:text-right lg:col-span-3
|
||||||
|
dark:border-gray-600
|
||||||
xl:col-span-2
|
xl:col-span-2
|
||||||
lg:grid-cols-1
|
lg:grid-cols-1
|
||||||
"
|
"
|
||||||
@ -77,6 +78,7 @@
|
|||||||
col-span-3
|
col-span-3
|
||||||
p-6
|
p-6
|
||||||
border-t border-gray-200 border-solid
|
border-t border-gray-200 border-solid
|
||||||
|
dark:border-gray-600
|
||||||
lg:justify-end lg:items-end lg:col-span-1
|
lg:justify-end lg:items-end lg:col-span-1
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
|||||||
@ -12,18 +12,24 @@
|
|||||||
hover:bg-gray-50
|
hover:bg-gray-50
|
||||||
xl:p-4
|
xl:p-4
|
||||||
lg:col-span-2
|
lg:col-span-2
|
||||||
|
dark:backdrop-blur-xl
|
||||||
|
dark:shadow-glass
|
||||||
|
dark:border
|
||||||
|
dark:border-white/10
|
||||||
|
dark:bg-gray-800/70
|
||||||
"
|
"
|
||||||
:class="{ 'lg:!col-span-3': large }"
|
:class="{ 'lg:!col-span-3': large }"
|
||||||
:to="route"
|
:to="route"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<span class="text-xl font-semibold leading-tight text-black xl:text-3xl">
|
<span class="text-xl font-semibold leading-tight text-black xl:text-3xl dark:text-white">
|
||||||
<slot />
|
<slot />
|
||||||
</span>
|
</span>
|
||||||
<span class="block mt-1 text-sm leading-tight text-gray-500 xl:text-lg">
|
<span class="block mt-1 text-sm leading-tight text-gray-500 xl:text-lg dark:text-gray-300">
|
||||||
{{ label }}
|
{{ label }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<BaseDarkHighlight class="!bg-highlight/[.17] !top-5" />
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<component :is="iconComponent" class="w-10 h-10 xl:w-12 xl:h-12" />
|
<component :is="iconComponent" class="w-10 h-10 xl:w-12 xl:h-12" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<BaseContentPlaceholders
|
<BaseContentPlaceholders
|
||||||
:rounded="true"
|
:rounded="true"
|
||||||
class="relative flex justify-between w-full p-3 bg-white rounded shadow lg:col-span-3 xl:p-4"
|
class="relative flex justify-between w-full p-3 bg-white rounded shadow lg:col-span-3 xl:p-4 dark:bg-gray-800"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<BaseContentPlaceholdersText
|
<BaseContentPlaceholdersText
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
shadow
|
shadow
|
||||||
lg:col-span-2
|
lg:col-span-2
|
||||||
xl:p-4
|
xl:p-4
|
||||||
|
dark:bg-gray-800
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -28,7 +28,7 @@
|
|||||||
<template #cell-user="{ row }">
|
<template #cell-user="{ row }">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ path: `invoices/${row.data.id}/view` }"
|
:to="{ path: `invoices/${row.data.id}/view` }"
|
||||||
class="font-medium text-primary-500"
|
class="font-medium text-primary-500 dark:text-primary-400"
|
||||||
>
|
>
|
||||||
{{ row.data.customer.name }}
|
{{ row.data.customer.name }}
|
||||||
</router-link>
|
</router-link>
|
||||||
@ -78,7 +78,7 @@
|
|||||||
<template #cell-user="{ row }">
|
<template #cell-user="{ row }">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ path: `estimates/${row.data.id}/view` }"
|
:to="{ path: `estimates/${row.data.id}/view` }"
|
||||||
class="font-medium text-primary-500"
|
class="font-medium text-primary-500 dark:text-primary-400"
|
||||||
>
|
>
|
||||||
{{ row.data.customer.name }}
|
{{ row.data.customer.name }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|||||||
@ -130,6 +130,7 @@
|
|||||||
mt-5
|
mt-5
|
||||||
list-none
|
list-none
|
||||||
border-b-2 border-gray-200 border-solid
|
border-b-2 border-gray-200 border-solid
|
||||||
|
dark:border-gray-600
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<!-- Tabs -->
|
<!-- Tabs -->
|
||||||
@ -163,7 +164,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<BaseDropdownItem @click="removeMultipleEstimates">
|
<BaseDropdownItem @click="removeMultipleEstimates">
|
||||||
<BaseIcon name="TrashIcon" class="mr-3 text-gray-600" />
|
<BaseIcon name="TrashIcon" class="mr-3 text-gray-600 dark:text-gray-400 dark:group-hover:text-white" />
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</BaseDropdown>
|
</BaseDropdown>
|
||||||
@ -204,7 +205,7 @@
|
|||||||
<template #cell-estimate_number="{ row }">
|
<template #cell-estimate_number="{ row }">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ path: `estimates/${row.data.id}/view` }"
|
:to="{ path: `estimates/${row.data.id}/view` }"
|
||||||
class="font-medium text-primary-500"
|
class="font-medium text-primary-500 dark:text-primary-400"
|
||||||
>
|
>
|
||||||
{{ row.data.estimate_number }}
|
{{ row.data.estimate_number }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|||||||
@ -50,6 +50,7 @@
|
|||||||
xl:ml-64
|
xl:ml-64
|
||||||
w-88
|
w-88
|
||||||
xl:block
|
xl:block
|
||||||
|
dark:bg-gray-800
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -62,6 +63,7 @@
|
|||||||
pb-2
|
pb-2
|
||||||
border border-gray-200 border-solid
|
border border-gray-200 border-solid
|
||||||
height-full
|
height-full
|
||||||
|
dark:border-gray-600
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
@ -96,9 +98,10 @@
|
|||||||
px-4
|
px-4
|
||||||
py-1
|
py-1
|
||||||
pb-2
|
pb-2
|
||||||
mb-1 mb-2
|
mb-2
|
||||||
text-sm
|
text-sm
|
||||||
border-b border-gray-200 border-solid
|
border-b border-gray-200 border-solid
|
||||||
|
dark:border-gray-600
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ $t('general.sort_by') }}
|
{{ $t('general.sort_by') }}
|
||||||
@ -161,6 +164,7 @@
|
|||||||
overflow-y-scroll
|
overflow-y-scroll
|
||||||
border-l border-gray-200 border-solid
|
border-l border-gray-200 border-solid
|
||||||
base-scroll
|
base-scroll
|
||||||
|
dark:border-gray-600
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div v-for="(estimate, index) in estimateList" :key="index">
|
<div v-for="(estimate, index) in estimateList" :key="index">
|
||||||
@ -169,9 +173,9 @@
|
|||||||
:id="'estimate-' + estimate.id"
|
:id="'estimate-' + estimate.id"
|
||||||
:to="`/admin/estimates/${estimate.id}/view`"
|
:to="`/admin/estimates/${estimate.id}/view`"
|
||||||
:class="[
|
:class="[
|
||||||
'flex justify-between side-estimate p-4 cursor-pointer hover:bg-gray-100 items-center border-l-4 border-transparent',
|
'flex justify-between side-estimate p-4 cursor-pointer hover:bg-gray-100 items-center border-l-4 border-transparent dark:hover:bg-gray-700',
|
||||||
{
|
{
|
||||||
'bg-gray-100 border-l-4 border-primary-500 border-solid':
|
'bg-gray-100 border-l-4 border-primary-500 border-solid dark:border-primary-400 dark:bg-gray-700':
|
||||||
hasActiveUrl(estimate.id),
|
hasActiveUrl(estimate.id),
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
@ -191,6 +195,7 @@
|
|||||||
text-black
|
text-black
|
||||||
capitalize
|
capitalize
|
||||||
truncate
|
truncate
|
||||||
|
dark:text-white
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -203,6 +208,7 @@
|
|||||||
font-medium
|
font-medium
|
||||||
leading-5
|
leading-5
|
||||||
text-gray-600
|
text-gray-600
|
||||||
|
dark:text-gray-400
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ estimate.estimate_number }}
|
{{ estimate.estimate_number }}
|
||||||
@ -228,6 +234,7 @@
|
|||||||
font-semibold
|
font-semibold
|
||||||
leading-8
|
leading-8
|
||||||
text-right text-gray-900
|
text-right text-gray-900
|
||||||
|
dark:text-white
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -239,6 +246,7 @@
|
|||||||
leading-5
|
leading-5
|
||||||
text-right text-gray-600
|
text-right text-gray-600
|
||||||
est-date
|
est-date
|
||||||
|
dark:text-gray-400
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ estimate.formatted_estimate_date }}
|
{{ estimate.formatted_estimate_date }}
|
||||||
@ -251,7 +259,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<p
|
<p
|
||||||
v-if="!estimateList?.length && !isLoading"
|
v-if="!estimateList?.length && !isLoading"
|
||||||
class="flex justify-center px-4 mt-5 text-sm text-gray-600"
|
class="flex justify-center px-4 mt-5 text-sm text-gray-600 dark:text-gray-300"
|
||||||
>
|
>
|
||||||
{{ $t('estimates.no_matching_estimates') }}
|
{{ $t('estimates.no_matching_estimates') }}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@ -138,7 +138,6 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref, watch, onMounted } from 'vue'
|
import { computed, ref, watch, onMounted } from 'vue'
|
||||||
import { cloneDeep } from 'lodash'
|
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import {
|
import {
|
||||||
@ -258,30 +257,11 @@ async function submitForm() {
|
|||||||
|
|
||||||
isSaving.value = true
|
isSaving.value = true
|
||||||
|
|
||||||
let data = cloneDeep({
|
let data = {
|
||||||
...estimateStore.newEstimate,
|
...estimateStore.newEstimate,
|
||||||
sub_total: estimateStore.getSubTotal,
|
sub_total: estimateStore.getSubTotal,
|
||||||
total: estimateStore.getTotal,
|
total: estimateStore.getTotal,
|
||||||
tax: estimateStore.getTotalTax,
|
tax: estimateStore.getTotalTax,
|
||||||
})
|
|
||||||
if (data.discount_per_item === 'YES') {
|
|
||||||
data.items.forEach((item, index) => {
|
|
||||||
if (item.discount_type === 'fixed'){
|
|
||||||
data.items[index].discount = Math.round(item.discount * 100)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (data.discount_type === 'fixed'){
|
|
||||||
data.discount = Math.round(data.discount * 100)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!estimateStore.newEstimate.tax_per_item === 'YES'
|
|
||||||
&& data.taxes.length
|
|
||||||
){
|
|
||||||
data.tax_type_ids = data.taxes.map(_t => _t.tax_type_id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const action = isEdit.value
|
const action = isEdit.value
|
||||||
|
|||||||
@ -32,6 +32,8 @@
|
|||||||
:content-loading="isLoading"
|
:content-loading="isLoading"
|
||||||
:calendar-button="true"
|
:calendar-button="true"
|
||||||
calendar-button-icon="calendar"
|
calendar-button-icon="calendar"
|
||||||
|
:show-extra-options="true"
|
||||||
|
:source-date="estimateStore.newEstimate.estimate_date"
|
||||||
/>
|
/>
|
||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
|||||||
@ -135,7 +135,7 @@
|
|||||||
v-if="userStore.hasAbilities(abilities.DELETE_EXPENSE)"
|
v-if="userStore.hasAbilities(abilities.DELETE_EXPENSE)"
|
||||||
@click="removeMultipleExpenses"
|
@click="removeMultipleExpenses"
|
||||||
>
|
>
|
||||||
<BaseIcon name="TrashIcon" class="h-5 mr-3 text-gray-600" />
|
<BaseIcon name="TrashIcon" class="h-5 mr-3 text-gray-600 dark:text-gray-400 dark:group-hover:text-white" />
|
||||||
{{ $t('general.delete') }}
|
{{ $t('general.delete') }}
|
||||||
</BaseDropdownItem>
|
</BaseDropdownItem>
|
||||||
</BaseDropdown>
|
</BaseDropdown>
|
||||||
@ -171,7 +171,7 @@
|
|||||||
<template #cell-name="{ row }">
|
<template #cell-name="{ row }">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ path: `expenses/${row.data.id}/edit` }"
|
:to="{ path: `expenses/${row.data.id}/edit` }"
|
||||||
class="font-medium text-primary-500"
|
class="font-medium text-primary-500 dark:text-primary-400"
|
||||||
>
|
>
|
||||||
{{ row.data.expense_category.name }}
|
{{ row.data.expense_category.name }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col items-center justify-between w-full pt-10">
|
<div class="flex flex-col items-center justify-between w-full pt-10">
|
||||||
|
<LightDarkButton class="absolute z-10 top-2 right-2"/>
|
||||||
<img
|
<img
|
||||||
id="logo-crater"
|
id="logo-crater"
|
||||||
src="/img/crater-logo.png"
|
src="/img/crater-logo.png"
|
||||||
@ -29,6 +30,7 @@ import Step7CompanyInfo from './Step7CompanyInfo.vue'
|
|||||||
import Step8CompanyPreferences from './Step8CompanyPreferences.vue'
|
import Step8CompanyPreferences from './Step8CompanyPreferences.vue'
|
||||||
import { useInstallationStore } from '@/scripts/admin/stores/installation'
|
import { useInstallationStore } from '@/scripts/admin/stores/installation'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
import LightDarkButton from '@/scripts/components/LightDarkButton.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -40,6 +42,7 @@ export default {
|
|||||||
step_6: Step6AccountSettings,
|
step_6: Step6AccountSettings,
|
||||||
step_7: Step7CompanyInfo,
|
step_7: Step7CompanyInfo,
|
||||||
step_8: Step8CompanyPreferences,
|
step_8: Step8CompanyPreferences,
|
||||||
|
LightDarkButton
|
||||||
},
|
},
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<div
|
<div
|
||||||
v-if="phpSupportInfo"
|
v-if="phpSupportInfo"
|
||||||
class="grid grid-flow-row grid-cols-3 p-3 border border-gray-200 lg:gap-24 sm:gap-4"
|
class="grid grid-flow-row grid-cols-3 p-3 border border-gray-200 lg:gap-24 sm:gap-4 dark:border-white/10"
|
||||||
>
|
>
|
||||||
<div class="col-span-2 text-sm">
|
<div class="col-span-2 text-sm">
|
||||||
{{
|
{{
|
||||||
@ -32,7 +32,7 @@
|
|||||||
<div
|
<div
|
||||||
v-for="(requirement, index) in requirements"
|
v-for="(requirement, index) in requirements"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="grid grid-flow-row grid-cols-3 p-3 border border-gray-200 lg:gap-24 sm:gap-4"
|
class="grid grid-flow-row grid-cols-3 p-3 border border-gray-200 dark:border-gray-600 lg:gap-24 sm:gap-4"
|
||||||
>
|
>
|
||||||
<div class="col-span-2 text-sm">
|
<div class="col-span-2 text-sm">
|
||||||
{{ index }}
|
{{ index }}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user