mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-03 22:47:32 -05:00 
			
		
		
		
	Import (#3360)
* Fixes for test data * Fixes for tests * Remove legacy vue components * Add routing number to client gateway tokens * working on important documents and company gateways * Import fixes
This commit is contained in:
		
							parent
							
								
									0e7904a74b
								
							
						
					
					
						commit
						c1d3fd12a8
					
				@ -98,7 +98,7 @@ class Creative extends AbstractDesign
 | 
			
		||||
        <tbody>
 | 
			
		||||
            $table_body
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td colspan="7" ref="note" class="px-4 py-4">$entity.public_notes</td>
 | 
			
		||||
                <td colspan="5" ref="note" class="px-4 py-4">$entity.public_notes</td>
 | 
			
		||||
                <td ref="quantity" class="px-4 py-4 flex flex-col">
 | 
			
		||||
                    $total_tax_labels
 | 
			
		||||
                    $line_tax_labels
 | 
			
		||||
 | 
			
		||||
@ -61,7 +61,7 @@ class InvoiceItemFactory
 | 
			
		||||
            $item->line_total = $item->quantity * $item->cost;
 | 
			
		||||
            $item->is_amount_discount = true;
 | 
			
		||||
            $item->discount = $faker->numberBetween(1, 10);
 | 
			
		||||
            $item->notes = $faker->realText(20);
 | 
			
		||||
            $item->notes = $faker->realText(50);
 | 
			
		||||
            $item->product_key = $faker->word();
 | 
			
		||||
            $item->custom_value1 = $faker->realText(10);
 | 
			
		||||
            $item->custom_value2 = $faker->realText(10);
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,9 @@
 | 
			
		||||
 *       @OA\Property(property="company_id", type="string", example="2", description="______"),
 | 
			
		||||
 *       @OA\Property(property="client_id", type="string", example="2", description="______"),
 | 
			
		||||
 *       @OA\Property(property="token", type="string", example="2", description="______"),
 | 
			
		||||
 *       @OA\Property(property="routing_number", type="string", example="2", description="______"),
 | 
			
		||||
 *       @OA\Property(property="company_gateway_id", type="string", example="2", description="______"),
 | 
			
		||||
 *       @OA\Property(property="is_default", type="boolean", example="true", description="______"),
 | 
			
		||||
 *       
 | 
			
		||||
 * )
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@ -143,6 +143,7 @@ class Import implements ShouldQueue
 | 
			
		||||
        $validator = Validator::make($data, $rules);
 | 
			
		||||
 | 
			
		||||
        if ($validator->fails()) {
 | 
			
		||||
            \Log::error($validator->errors());
 | 
			
		||||
            throw new MigrationValidatorFailed($validator->errors());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -444,11 +445,11 @@ class Import implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
            $old_user_key = array_key_exists('user_id', $resource) ?? $this->user->id;
 | 
			
		||||
            
 | 
			
		||||
            $this->ids['quotes'] = [
 | 
			
		||||
                "quotes_{$old_user_key}" => [
 | 
			
		||||
                    'old' => $old_user_key,
 | 
			
		||||
            $key = "invoices_{$resource['id']}";
 | 
			
		||||
 | 
			
		||||
            $this->ids['quotes'][$key] = [
 | 
			
		||||
                'old' => $resource['id'],
 | 
			
		||||
                'new' => $invoice->id,
 | 
			
		||||
                ]
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
@ -517,10 +518,12 @@ class Import implements ShouldQueue
 | 
			
		||||
            $modified = $resource;
 | 
			
		||||
 | 
			
		||||
            if (array_key_exists('invoice_id', $resource) && !array_key_exists('invoices', $this->ids)) {
 | 
			
		||||
                \Log::error("ivoice id missing");
 | 
			
		||||
                throw new ResourceDependencyMissing(array_key_first($data), 'invoices');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (array_key_exists('expense_id', $resource) && !array_key_exists('expenses', $this->ids)) {
 | 
			
		||||
                \Log::error("expense id missing");
 | 
			
		||||
                throw new ResourceDependencyMissing(array_key_first($data), 'expenses');
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
@ -534,21 +537,21 @@ class Import implements ShouldQueue
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(array_key_exists('expense_id', $resource) && $resource['expense_id']) {
 | 
			
		||||
                $modified['documentable_id'] = $this->transformId('expense', $resource['expense_id']);
 | 
			
		||||
                $modified['documentable_id'] = $this->transformId('expenses', $resource['expense_id']);
 | 
			
		||||
                $modified['documentable_type'] = 'App\\Models\\Expense';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $modified['user_id'] = $this->processUserId($resource);
 | 
			
		||||
            $modified['company_id'] = $this->company->id;
 | 
			
		||||
 | 
			
		||||
            $payment = Document::create($modified);
 | 
			
		||||
            $document = Document::create($modified);
 | 
			
		||||
 | 
			
		||||
            $old_user_key = array_key_exists('user_id', $resource) ?? $this->user->id;
 | 
			
		||||
 | 
			
		||||
            $this->ids['payments'] = [
 | 
			
		||||
                "payments_{$old_user_key}" => [
 | 
			
		||||
            $this->ids['documents'] = [
 | 
			
		||||
                "documents_{$old_user_key}" => [
 | 
			
		||||
                    'old' => $old_user_key,
 | 
			
		||||
                    'new' => $payment->id,
 | 
			
		||||
                    'new' => $document->id,
 | 
			
		||||
                ]
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,7 @@ use App\Models\DateFormat;
 | 
			
		||||
use App\Models\Filterable;
 | 
			
		||||
use App\Models\Paymentable;
 | 
			
		||||
use App\Services\Ledger\LedgerService;
 | 
			
		||||
use App\Services\Payment\PaymentService;
 | 
			
		||||
use App\Utils\Number;
 | 
			
		||||
use App\Utils\Traits\MakesDates;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
@ -175,6 +176,11 @@ class Payment extends BaseModel
 | 
			
		||||
        return new LedgerService($this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function service()
 | 
			
		||||
    {
 | 
			
		||||
        return new PaymentService($this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function resolveRouteBinding($value)
 | 
			
		||||
    {
 | 
			
		||||
        return $this
 | 
			
		||||
 | 
			
		||||
@ -178,7 +178,7 @@ class StripePaymentDriver extends BasePaymentDriver
 | 
			
		||||
            $payment_meta->exp_year = $stripe_payment_method_obj['card']['exp_year'];
 | 
			
		||||
            $payment_meta->brand = $stripe_payment_method_obj['card']['brand'];
 | 
			
		||||
            $payment_meta->last4 = $stripe_payment_method_obj['card']['last4'];
 | 
			
		||||
            $payment_meta->type = $stripe_payment_method_obj['type'];
 | 
			
		||||
            $payment_meta->type = GatewayType::CREDIT_CARD;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $cgt = new ClientGatewayToken;
 | 
			
		||||
 | 
			
		||||
@ -5,13 +5,12 @@ use App\Credit;
 | 
			
		||||
 | 
			
		||||
class CreditService
 | 
			
		||||
{
 | 
			
		||||
    protected $credit;
 | 
			
		||||
    
 | 
			
		||||
    protected $credit;
 | 
			
		||||
 | 
			
		||||
    public function __construct($credit)
 | 
			
		||||
    {
 | 
			
		||||
        $this->credit = $credit;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getCreditPdf($contact)
 | 
			
		||||
@ -44,6 +43,7 @@ class CreditService
 | 
			
		||||
    public function save() : ?Credit
 | 
			
		||||
    {
 | 
			
		||||
        $this->credit->save();
 | 
			
		||||
 | 
			
		||||
        return $this->credit;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -29,7 +29,7 @@ class UpdateInvoicePayment
 | 
			
		||||
                
 | 
			
		||||
                $this->payment
 | 
			
		||||
                     ->ledger()
 | 
			
		||||
                     ->updatePaymentBalance($this->payment, ($invoice->balance*-1));
 | 
			
		||||
                     ->updatePaymentBalance($invoice->balance*-1);
 | 
			
		||||
                
 | 
			
		||||
                $this->payment->client
 | 
			
		||||
                    ->service()
 | 
			
		||||
@ -66,7 +66,7 @@ class UpdateInvoicePayment
 | 
			
		||||
 | 
			
		||||
                        $this->payment
 | 
			
		||||
                             ->ledger()
 | 
			
		||||
                             ->updatePaymentBalance($this->payment, ($invoice->partial*-1));
 | 
			
		||||
                             ->updatePaymentBalance($invoice->partial*-1);
 | 
			
		||||
 | 
			
		||||
                        $this->payment->client->service()
 | 
			
		||||
                                                ->updateBalance($invoice->partial*-1)
 | 
			
		||||
@ -85,7 +85,7 @@ class UpdateInvoicePayment
 | 
			
		||||
                        
 | 
			
		||||
                        $this->payment
 | 
			
		||||
                             ->ledger()
 | 
			
		||||
                             ->updatePaymentBalance($this->payment, ($invoice->balance*-1));
 | 
			
		||||
                             ->updatePaymentBalance($invoice->balance*-1);
 | 
			
		||||
 | 
			
		||||
                        $this->payment->client->service()
 | 
			
		||||
                                              ->updateBalance($invoice->balance*-1)
 | 
			
		||||
 | 
			
		||||
@ -1128,6 +1128,7 @@ class CreateUsersTable extends Migration
 | 
			
		||||
            $table->unsignedInteger('company_id');
 | 
			
		||||
            $table->unsignedInteger('client_id')->nullable();
 | 
			
		||||
            $table->text('token')->nullable();
 | 
			
		||||
            $table->text('routing_number')->nullable();
 | 
			
		||||
            $table->unsignedInteger('company_gateway_id');
 | 
			
		||||
            $table->string('gateway_customer_reference')->nullable();
 | 
			
		||||
            $table->unsignedInteger('gateway_type_id');
 | 
			
		||||
 | 
			
		||||
@ -8,8 +8,6 @@ use App\Events\Invoice\InvoiceWasUpdated;
 | 
			
		||||
use App\Events\Payment\PaymentWasCreated;
 | 
			
		||||
use App\Helpers\Invoice\InvoiceSum;
 | 
			
		||||
use App\Helpers\Invoice\InvoiceSumInclusive;
 | 
			
		||||
use App\Jobs\Company\UpdateCompanyLedgerWithInvoice;
 | 
			
		||||
//use App\Jobs\Invoice\UpdateInvoicePayment;
 | 
			
		||||
use App\Listeners\Credit\CreateCreditInvitation;
 | 
			
		||||
use App\Listeners\Invoice\CreateInvoiceInvitation;
 | 
			
		||||
use App\Models\Account;
 | 
			
		||||
@ -165,7 +163,7 @@ class RandomDataSeeder extends Seeder
 | 
			
		||||
 | 
			
		||||
            event(new CreateInvoiceInvitation($invoice));
 | 
			
		||||
 | 
			
		||||
            UpdateCompanyLedgerWithInvoice::dispatchNow($invoice, $invoice->balance, $invoice->company);
 | 
			
		||||
            $invoice->ledger()->updateInvoiceBalance($invoice->balance);
 | 
			
		||||
 | 
			
		||||
            $invoice->service()->markSent()->save();
 | 
			
		||||
 | 
			
		||||
@ -187,7 +185,7 @@ class RandomDataSeeder extends Seeder
 | 
			
		||||
 | 
			
		||||
                event(new PaymentWasCreated($payment, $payment->company));
 | 
			
		||||
 | 
			
		||||
                $payment->service()->UpdateInvoicePayment();
 | 
			
		||||
                $payment->service()->updateInvoicePayment();
 | 
			
		||||
 | 
			
		||||
    //            UpdateInvoicePayment::dispatchNow($payment, $payment->company);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								jest.config.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								jest.config.js
									
									
									
									
										vendored
									
									
								
							@ -1,17 +0,0 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  "roots": [
 | 
			
		||||
    "resources/js/src"
 | 
			
		||||
  ],
 | 
			
		||||
  "transform": {
 | 
			
		||||
    "^.+\\.tsx?$": "ts-jest"
 | 
			
		||||
  },
 | 
			
		||||
  "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
 | 
			
		||||
  "moduleFileExtensions": [
 | 
			
		||||
    "ts",
 | 
			
		||||
    "tsx",
 | 
			
		||||
    "js",
 | 
			
		||||
    "jsx",
 | 
			
		||||
    "json",
 | 
			
		||||
    "node"
 | 
			
		||||
  ],
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										106
									
								
								resources/assets/js/vendor/I18n.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										106
									
								
								resources/assets/js/vendor/I18n.js
									
									
									
									
										vendored
									
									
								
							@ -1,106 +0,0 @@
 | 
			
		||||
export default class I18n
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize a new translation instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  {string}  key
 | 
			
		||||
     * @return {void}
 | 
			
		||||
     */
 | 
			
		||||
    constructor(key = 'translations')
 | 
			
		||||
    {
 | 
			
		||||
        this.key = key;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get and replace the string of the given key.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  {string}  key
 | 
			
		||||
     * @param  {object}  replace
 | 
			
		||||
     * @return {string}
 | 
			
		||||
     */
 | 
			
		||||
    trans(key, replace = {})
 | 
			
		||||
    {
 | 
			
		||||
        return this._replace(this._extract(key), replace);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get and pluralize the strings of the given key.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  {string}  key
 | 
			
		||||
     * @param  {number}  count
 | 
			
		||||
     * @param  {object}  replace
 | 
			
		||||
     * @return {string}
 | 
			
		||||
     */
 | 
			
		||||
    trans_choice(key, count = 1, replace = {})
 | 
			
		||||
    {
 | 
			
		||||
        let translations = this._extract(key, '|').split('|'), translation;
 | 
			
		||||
 | 
			
		||||
        translations.some(t => translation = this._match(t, count));
 | 
			
		||||
 | 
			
		||||
        translation = translation || (count > 1 ? translations[1] : translations[0]);
 | 
			
		||||
 | 
			
		||||
        return this._replace(translation, replace);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Match the translation limit with the count.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  {string}  translation
 | 
			
		||||
     * @param  {number}  count
 | 
			
		||||
     * @return {string|null}
 | 
			
		||||
     */
 | 
			
		||||
    _match(translation, count)
 | 
			
		||||
    {
 | 
			
		||||
        let match = translation.match(/^[\{\[]([^\[\]\{\}]*)[\}\]](.*)/);
 | 
			
		||||
 | 
			
		||||
        if (! match) return;
 | 
			
		||||
 | 
			
		||||
        if (match[1].includes(',')) {
 | 
			
		||||
            let [from, to] = match[1].split(',');
 | 
			
		||||
 | 
			
		||||
            if (to === '*' && count >= from) {
 | 
			
		||||
                return match[2];
 | 
			
		||||
            } else if (from === '*' && count <= to) {
 | 
			
		||||
                return match[2];
 | 
			
		||||
            } else if (count >= from && count <= to) {
 | 
			
		||||
                return match[2];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return match[1] == count ? match[2] : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Replace the placeholders.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  {string}  translation
 | 
			
		||||
     * @param  {object}  replace
 | 
			
		||||
     * @return {string}
 | 
			
		||||
     */
 | 
			
		||||
    _replace(translation, replace)
 | 
			
		||||
    {
 | 
			
		||||
        for (let placeholder in replace) {
 | 
			
		||||
            translation = translation
 | 
			
		||||
                .replace(`:${placeholder}`, replace[placeholder])
 | 
			
		||||
                .replace(`:${placeholder.toUpperCase()}`, replace[placeholder].toUpperCase())
 | 
			
		||||
                .replace(
 | 
			
		||||
                    `:${placeholder.charAt(0).toUpperCase()}${placeholder.slice(1)}`,
 | 
			
		||||
                    replace[placeholder].charAt(0).toUpperCase()+replace[placeholder].slice(1)
 | 
			
		||||
                );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return translation.trim();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The extract helper.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  {string}  key
 | 
			
		||||
     * @param  {mixed}  value
 | 
			
		||||
     * @return {mixed}
 | 
			
		||||
     */
 | 
			
		||||
    _extract(key, value = null)
 | 
			
		||||
    {
 | 
			
		||||
        return key.toString().split('.').reduce((t, i) => t[i] || (value || key), window[this.key]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81762
									
								
								resources/assets/js/vue-i18n-locales.generated.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										81762
									
								
								resources/assets/js/vue-i18n-locales.generated.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										61
									
								
								resources/js/src/bootstrap.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										61
									
								
								resources/js/src/bootstrap.js
									
									
									
									
										vendored
									
									
								
							@ -1,61 +0,0 @@
 | 
			
		||||
// lodash handles our translations 
 | 
			
		||||
import * as get from "lodash.get"
 | 
			
		||||
 | 
			
		||||
// import Toastr
 | 
			
		||||
import Toastr from 'vue-toastr';
 | 
			
		||||
 | 
			
		||||
// Import toastr scss file: need webpack sass-loader
 | 
			
		||||
require('vue-toastr/src/vue-toastr.scss');
 | 
			
		||||
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
 | 
			
		||||
// Register vue component
 | 
			
		||||
Vue.component('vue-toastr',Toastr);
 | 
			
		||||
 | 
			
		||||
// Global translation helper
 | 
			
		||||
Vue.prototype.trans = string => get(i18n, string);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
window.axios = require('axios');
 | 
			
		||||
window.Vue = require('vue');
 | 
			
		||||
 | 
			
		||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
 | 
			
		||||
 | 
			
		||||
/* Development only*/
 | 
			
		||||
Vue.config.devtools = true;
 | 
			
		||||
 | 
			
		||||
window.axios.defaults.headers.common = {
 | 
			
		||||
    'X-Requested-With': 'XMLHttpRequest',
 | 
			
		||||
    'X-CSRF-TOKEN' : document.querySelector('meta[name="csrf-token"]').getAttribute('content')
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Next we will register the CSRF Token as a common header with Axios so that
 | 
			
		||||
 * all outgoing HTTP requests automatically have it attached. This is just
 | 
			
		||||
 * a simple convenience so we don't have to attach every token manually.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
let token = document.head.querySelector('meta[name="csrf-token"]');
 | 
			
		||||
 | 
			
		||||
if (token) {
 | 
			
		||||
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
 | 
			
		||||
} else {
 | 
			
		||||
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Echo exposes an expressive API for subscribing to channels and listening
 | 
			
		||||
 * for events that are broadcast by Laravel. Echo and event broadcasting
 | 
			
		||||
 * allows your team to easily build robust real-time web applications.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// import Echo from 'laravel-echo'
 | 
			
		||||
 | 
			
		||||
// window.Pusher = require('pusher-js');
 | 
			
		||||
 | 
			
		||||
// window.Echo = new Echo({
 | 
			
		||||
//     broadcaster: 'pusher',
 | 
			
		||||
//     key: process.env.MIX_PUSHER_APP_KEY,
 | 
			
		||||
//     cluster: process.env.MIX_PUSHER_APP_CLUSTER,
 | 
			
		||||
//     encrypted: true
 | 
			
		||||
// });
 | 
			
		||||
@ -1,70 +0,0 @@
 | 
			
		||||
//import * as Vue from 'vue';
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
import Form from '../utils/form';
 | 
			
		||||
import Client from '../models/client-model';
 | 
			
		||||
 | 
			
		||||
// import Toastr
 | 
			
		||||
import Toastr from 'vue-toastr';
 | 
			
		||||
// import toastr scss file: need webpack sass-loader
 | 
			
		||||
require('vue-toastr/src/vue-toastr.scss');
 | 
			
		||||
// Register vue component
 | 
			
		||||
Vue.component('vue-toastr',Toastr);
 | 
			
		||||
 | 
			
		||||
declare var client_object: any;
 | 
			
		||||
declare var hashed_id: string;
 | 
			
		||||
 | 
			
		||||
 new Vue({
 | 
			
		||||
    el : '#client_create',
 | 
			
		||||
    data: function () {
 | 
			
		||||
        return {
 | 
			
		||||
            form: new Form(<Client>client_object)
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    methods:{
 | 
			
		||||
        remove(this:any, contact:any){
 | 
			
		||||
            let index = this.form.contacts.indexOf(contact);
 | 
			
		||||
            this.form.contacts.splice(index, 1);
 | 
			
		||||
        },
 | 
			
		||||
        add(this: any){
 | 
			
		||||
            this.form.contacts.push({first_name: '', last_name: '', email: '', phone: '', id: 0});
 | 
			
		||||
            window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight);
 | 
			
		||||
            this.$nextTick(() => {
 | 
			
		||||
                     let index = this.form.contacts.length - 1;
 | 
			
		||||
                     let input = this.$refs.first_name[index];
 | 
			
		||||
                     input.focus();
 | 
			
		||||
                  });
 | 
			
		||||
        },
 | 
			
		||||
        onSubmit() {
 | 
			
		||||
            this.form.post('/clients/')
 | 
			
		||||
                .then(response => {
 | 
			
		||||
                    this.$root.$refs.toastr.s("Created client"); //how are we going to handle translations here?
 | 
			
		||||
                        
 | 
			
		||||
                    window.location.href = '/clients/' + this.form.hashed_id + '/edit';
 | 
			
		||||
 | 
			
		||||
                })
 | 
			
		||||
                .catch(error => {
 | 
			
		||||
 | 
			
		||||
                    this.$root.$refs.toastr.e("Error saving client");
 | 
			
		||||
 | 
			
		||||
                });
 | 
			
		||||
        },
 | 
			
		||||
        copy(type: any) {
 | 
			
		||||
            if(type.includes('copy_billing')){
 | 
			
		||||
                this.form.shipping_address1 = this.form.address1; 
 | 
			
		||||
                this.form.shipping_address2 = this.form.address2; 
 | 
			
		||||
                this.form.shipping_city = this.form.city; 
 | 
			
		||||
                this.form.shipping_state = this.form.state; 
 | 
			
		||||
                this.form.shipping_postal_code = this.form.postal_code; 
 | 
			
		||||
                this.form.shipping_country_id = this.form.country_id; 
 | 
			
		||||
                }else {
 | 
			
		||||
                this.form.address1 = this.form.shipping_address1; 
 | 
			
		||||
                this.form.address2 = this.form.shipping_address2; 
 | 
			
		||||
                this.form.city = this.form.shipping_city; 
 | 
			
		||||
                this.form.state = this.form.shipping_state; 
 | 
			
		||||
                this.form.postal_code = this.form.shipping_postal_code; 
 | 
			
		||||
                this.form.country_id = this.form.shipping_country_id; 
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@ -1,24 +0,0 @@
 | 
			
		||||
/* Allows us to use our native translation easily using {{ trans() }} syntax */
 | 
			
		||||
//const _ = require('lodash');
 | 
			
		||||
 | 
			
		||||
require('../bootstrap');
 | 
			
		||||
 | 
			
		||||
/* Must be declare in every child view*/
 | 
			
		||||
declare var i18n;
 | 
			
		||||
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
 | 
			
		||||
Vue.component('client-edit', require('../components/client/ClientEdit.vue'));
 | 
			
		||||
Vue.component('client-address', require('../components/client/ClientAddress.vue'));
 | 
			
		||||
Vue.component('generic-address', require('../components/generic/Address.vue'));
 | 
			
		||||
Vue.component('client-edit-form', require('../components/client/ClientEditForm.vue'));
 | 
			
		||||
Vue.component('contact-edit', require('../components/client/ClientContactEdit.vue'));
 | 
			
		||||
Vue.component('client-settings', require('../components/client/ClientSettings.vue'));
 | 
			
		||||
 | 
			
		||||
window.onload = function () {
 | 
			
		||||
 | 
			
		||||
    const app = new Vue({
 | 
			
		||||
        el: '#client_edit'
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,30 +0,0 @@
 | 
			
		||||
require('../bootstrap');
 | 
			
		||||
 | 
			
		||||
/* Must be declare in every child view*/
 | 
			
		||||
declare var i18n;
 | 
			
		||||
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
import store from '../store'
 | 
			
		||||
 | 
			
		||||
export default store
 | 
			
		||||
 | 
			
		||||
Vue.component('client-list', require('../components/client/ClientList.vue'));
 | 
			
		||||
Vue.component('client-actions', require('../components/client/ClientActions.vue'));
 | 
			
		||||
Vue.component('vuetable', require('vuetable-2/src/components/Vuetable'));
 | 
			
		||||
Vue.component('vuetable-pagination', require('vuetable-2/src/components/VuetablePagination'));
 | 
			
		||||
Vue.component('vuetable-pagination-bootstrap', require('../components/util/VuetablePaginationBootstrap'));
 | 
			
		||||
Vue.component('vuetable-filter-bar', require('../components/util/VuetableFilterBar'));
 | 
			
		||||
Vue.component('vuetable-query-filter', require('../components/client/ClientFilters.vue'));
 | 
			
		||||
Vue.component('vuetable-multi-select', require('../components/util/VuetableMultiSelect.vue'));
 | 
			
		||||
Vue.component('list-actions', require('../components/util/VueListActions.vue'));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
window.onload = function () {
 | 
			
		||||
 | 
			
		||||
    const app = new Vue({
 | 
			
		||||
        el: '#client_list',
 | 
			
		||||
        store 
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,20 +0,0 @@
 | 
			
		||||
/* Allows us to use our native translation easily using {{ trans() }} syntax */
 | 
			
		||||
//const _ = require('lodash');
 | 
			
		||||
 | 
			
		||||
require('../bootstrap');
 | 
			
		||||
 | 
			
		||||
/* Must be declare in every child view*/
 | 
			
		||||
declare var i18n;
 | 
			
		||||
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
 | 
			
		||||
Vue.component('client-show', require('../components/client/ClientShow.vue'));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
window.onload = function () {
 | 
			
		||||
 | 
			
		||||
    const app = new Vue({
 | 
			
		||||
        el: '#client_show'
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,52 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
 | 
			
		||||
	<div class="dropdown">
 | 
			
		||||
		<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
 | 
			
		||||
		{{ trans('texts.select') }}
 | 
			
		||||
		</button>
 | 
			
		||||
			<div class="dropdown-menu" aria-labelledby="dropdownMenu">
 | 
			
		||||
				<a class="dropdown-item" :href="action.url" v-for="action in rowData.actions">{{ action.name }}</a>
 | 
			
		||||
        <div class="dropdown-divider"></div>
 | 
			
		||||
        <a class="dropdown-item" href="#" @click="itemAction('archive', rowData, rowIndex)" v-if="rowData.deleted_at == null">{{ trans('texts.archive') }}</a>
 | 
			
		||||
        <a class="dropdown-item" href="#" @click="itemAction('restore', rowData, rowIndex)" v-if="rowData.is_deleted == 1 || rowData.deleted_at != null">{{ trans('texts.restore') }}</a>
 | 
			
		||||
        <a class="dropdown-item" href="#" @click="itemAction('delete', rowData, rowIndex)" v-if="rowData.is_deleted == 0">{{ trans('texts.delete') }}</a>
 | 
			
		||||
			</div>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  export default {
 | 
			
		||||
    props: {
 | 
			
		||||
      rowData: {
 | 
			
		||||
        type: Object,
 | 
			
		||||
        required: true
 | 
			
		||||
      },
 | 
			
		||||
      rowIndex: {
 | 
			
		||||
        type: Number
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      itemAction (action, data, index) {
 | 
			
		||||
 | 
			
		||||
        this.$events.fire('single-action', {'action': action, 'ids': [data.id]})
 | 
			
		||||
      
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
	.custom-actions button.ui.button {
 | 
			
		||||
	  padding: 8px 8px;
 | 
			
		||||
	}
 | 
			
		||||
	.custom-actions button.ui.button > i.icon {
 | 
			
		||||
	  margin: auto !important;
 | 
			
		||||
	}
 | 
			
		||||
  .dropdown-item {
 | 
			
		||||
    outline:0px; 
 | 
			
		||||
    border:0px; 
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@ -1,180 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div>
 | 
			
		||||
		<ul class="nav nav-tabs" role="tablist">
 | 
			
		||||
			<li class="nav-item">
 | 
			
		||||
				<a class="nav-link active" data-toggle="tab" href="#billing" role="tab" aria-controls="billing">{{ trans('texts.billing_address') }}</a>
 | 
			
		||||
			</li>
 | 
			
		||||
			<li class="nav-item">
 | 
			
		||||
				<a class="nav-link" data-toggle="tab" href="#shipping" role="tab" aria-controls="shipping">{{ trans('texts.shipping_address') }}</a>
 | 
			
		||||
			</li>
 | 
			
		||||
		</ul>
 | 
			
		||||
		<div class="tab-content">
 | 
			
		||||
			<div class="tab-pane active" id="billing" role="tabpanel">
 | 
			
		||||
				<button type="button" class="btn btn-sm btn-light" v-on:click="$emit('copy', 'copy_shipping')"> {{ trans('texts.copy_shipping') }}</button>
 | 
			
		||||
				<div class="card-body">
 | 
			
		||||
				    <div class="form-group row">
 | 
			
		||||
				        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.address1') }}</label>
 | 
			
		||||
				        <div class="col-sm-9">
 | 
			
		||||
				            <input type="text" :placeholder="trans('texts.address1')" v-model="client.address1" class="form-control">
 | 
			
		||||
                 			<div v-if="client.errors.has('address1')" class="text-danger" v-text="client.errors.get('address1')"></div>
 | 
			
		||||
				        </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
 | 
			
		||||
				    <div class="form-group row">
 | 
			
		||||
				        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.address2') }}</label>
 | 
			
		||||
				        <div class="col-sm-9">
 | 
			
		||||
				            <input type="text":placeholder="trans('texts.address2')" v-model="client.address2" class="form-control">
 | 
			
		||||
                 			<div v-if="client.errors.has('address2')" class="text-danger" v-text="client.errors.get('address2')"></div>
 | 
			
		||||
				        </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
 | 
			
		||||
				    <div class="form-group row">
 | 
			
		||||
				        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.city') }}</label>
 | 
			
		||||
				        <div class="col-sm-9">
 | 
			
		||||
				            <input type="text":placeholder="trans('texts.city')" v-model="client.city" class="form-control">
 | 
			
		||||
                 			<div v-if="client.errors.has('city')" class="text-danger" v-text="client.errors.get('city')"></div>
 | 
			
		||||
				        </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
 | 
			
		||||
				    <div class="form-group row">
 | 
			
		||||
				        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.state') }}</label>
 | 
			
		||||
				        <div class="col-sm-9">
 | 
			
		||||
				            <input type="text" :placeholder="trans('texts.state')" v-model="client.state" class="form-control">
 | 
			
		||||
                 			<div v-if="client.errors.has('state')" class="text-danger" v-text="client.errors.get('state')"></div>
 | 
			
		||||
				        </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
 | 
			
		||||
				    <div class="form-group row">
 | 
			
		||||
				        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.postal_code') }}</label>
 | 
			
		||||
				        <div class="col-sm-9">
 | 
			
		||||
				            <input type="text" :placeholder="trans('texts.postal_code')" v-model="client.postal_code" class="form-control">
 | 
			
		||||
                 			<div v-if="client.errors.has('postal_code')" class="text-danger" v-text="client.errors.get('postal_code')"></div>
 | 
			
		||||
				        </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
 | 
			
		||||
				    <div class="form-group row">
 | 
			
		||||
				        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.country') }}</label>
 | 
			
		||||
				        <div class="col-sm-9">
 | 
			
		||||
			            	<multiselect v-model="billingCountry" :options="options" :placeholder="trans('texts.country')" label="name" track-by="id" @input="onChangeBilling"></multiselect>
 | 
			
		||||
                 			<div v-if="client.errors.has('country_id')" class="text-danger" v-text="client.errors.get('country_id')"></div>
 | 
			
		||||
				        </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
				</div>	
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="tab-pane" id="shipping" role="tabpanel">
 | 
			
		||||
				<button type="button" class="btn btn-sm btn-light" v-on:click="$emit('copy',' copy_billing')"> {{ trans('texts.copy_billing') }}</button>
 | 
			
		||||
				<div class="form-group row">
 | 
			
		||||
				        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.address1') }}</label>
 | 
			
		||||
				        <div class="col-sm-9">
 | 
			
		||||
				            <input type="text" :placeholder="trans('texts.address1')" v-model="client.shipping_address1" class="form-control">
 | 
			
		||||
                 			<div v-if="client.errors.has('shipping_address1')" class="text-danger" v-text="client.errors.get('shipping_address1')"></div>
 | 
			
		||||
				        </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
 | 
			
		||||
				    <div class="form-group row">
 | 
			
		||||
				        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.address2') }}</label>
 | 
			
		||||
				        <div class="col-sm-9">
 | 
			
		||||
				            <input type="text" :placeholder="trans('texts.address2')" v-model="client.shipping_address2" class="form-control">
 | 
			
		||||
                 			<div v-if="client.errors.has('shipping_address2')" class="text-danger" v-text="client.errors.get('shipping_address2')"></div>
 | 
			
		||||
				        </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
 | 
			
		||||
				    <div class="form-group row">
 | 
			
		||||
				        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.city') }}</label>
 | 
			
		||||
				        <div class="col-sm-9">
 | 
			
		||||
				            <input type="text" :placeholder="trans('texts.city')" v-model="client.shipping_city" class="form-control">
 | 
			
		||||
                 			<div v-if="client.errors.has('shipping_city')" class="text-danger" v-text="client.errors.get('shipping_city')"></div>
 | 
			
		||||
				        </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
 | 
			
		||||
				    <div class="form-group row">
 | 
			
		||||
				        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.state') }}</label>
 | 
			
		||||
				        <div class="col-sm-9">
 | 
			
		||||
				            <input type="text" :placeholder="trans('texts.state')" v-model="client.shipping_state" class="form-control">
 | 
			
		||||
                 			<div v-if="client.errors.has('shipping_state')" class="text-danger" v-text="client.errors.get('shipping_state')"></div>
 | 
			
		||||
				        </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
 | 
			
		||||
				    <div class="form-group row">
 | 
			
		||||
				        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.postal_code') }}</label>
 | 
			
		||||
				        <div class="col-sm-9">
 | 
			
		||||
				            <input type="text" :placeholder="trans('texts.postal_code')" v-model="client.shipping_postal_code" class="form-control">
 | 
			
		||||
                 			<div v-if="client.errors.has('shipping_postal_code')" class="text-danger" v-text="client.errors.get('shipping_postal_code')"></div>
 | 
			
		||||
				        </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
 | 
			
		||||
				    <div class="form-group row">
 | 
			
		||||
				        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.country') }}</label>
 | 
			
		||||
				        <div class="col-sm-9">
 | 
			
		||||
			            	<multiselect v-model="shippingCountry" :options="options" :placeholder="trans('texts.country')" label="name" track-by="id" @input="onChangeShipping"></multiselect>
 | 
			
		||||
             				<div v-if="client.errors.has('shipping_country_id')" class="text-danger" v-text="client.errors.get('shipping_country_id')"></div>
 | 
			
		||||
				        </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
				</div>	
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>	
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
	import Multiselect from 'vue-multiselect'
 | 
			
		||||
 | 
			
		||||
	export default {
 | 
			
		||||
		components: {
 | 
			
		||||
		    Multiselect
 | 
			
		||||
		  },
 | 
			
		||||
        props: ['client', 'countries'],
 | 
			
		||||
        mounted() {
 | 
			
		||||
        },
 | 
			
		||||
        data () {
 | 
			
		||||
		    return {
 | 
			
		||||
		      options: Object.keys(this.countries).map(i => this.countries[i]),
 | 
			
		||||
		      countryArray: Object.keys(this.countries).map(i => this.countries[i])
 | 
			
		||||
		    }
 | 
			
		||||
		  },
 | 
			
		||||
		computed: {
 | 
			
		||||
	        shippingCountry: {
 | 
			
		||||
	            set: function() {
 | 
			
		||||
	            
 | 
			
		||||
	              //  return this.client.shipping_country_id
 | 
			
		||||
	            
 | 
			
		||||
	            },
 | 
			
		||||
	            get: function(value) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	            	return this.countryArray.filter(obj => {
 | 
			
		||||
					  return obj.id === this.client.shipping_country_id
 | 
			
		||||
					})
 | 
			
		||||
 | 
			
		||||
	            }
 | 
			
		||||
	        },
 | 
			
		||||
	        billingCountry: {
 | 
			
		||||
	            set: function() {
 | 
			
		||||
	            
 | 
			
		||||
	                return this.client.country_id
 | 
			
		||||
	            
 | 
			
		||||
	            },
 | 
			
		||||
	            get: function(value) {
 | 
			
		||||
 | 
			
		||||
	            	return this.countryArray.filter(obj => {
 | 
			
		||||
					  return obj.id === this.client.country_id
 | 
			
		||||
					})
 | 
			
		||||
 | 
			
		||||
	            }
 | 
			
		||||
	        }
 | 
			
		||||
 | 
			
		||||
	    },
 | 
			
		||||
	  	methods: {
 | 
			
		||||
	  		onChangeShipping(value) {
 | 
			
		||||
	  			this.client.shipping_country_id = value.id
 | 
			
		||||
	  		},
 | 
			
		||||
	  		onChangeBilling(value) {
 | 
			
		||||
	  			this.client.country_id = value.id
 | 
			
		||||
	  		}
 | 
			
		||||
	  	}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
 | 
			
		||||
@ -1,76 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="card-body">
 | 
			
		||||
        <div class="form-group row">
 | 
			
		||||
            <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.first_name') }}</label>
 | 
			
		||||
            <div class="col-sm-9">
 | 
			
		||||
                <input ref="first_name" name="first_name" type="text" :placeholder="trans('texts.first_name')" v-model="contact.first_name" class="form-control">
 | 
			
		||||
                <div v-if="form.errors.has('contacts.'+error_index+'.first_name')" class="text-danger" v-text="form.errors.get('contacts.'+error_index+'.first_name')"></div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group row">
 | 
			
		||||
            <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.last_name') }}</label>
 | 
			
		||||
            <div class="col-sm-9">
 | 
			
		||||
                <input type="text" :placeholder="trans('texts.last_name')" v-model="contact.last_name" class="form-control">
 | 
			
		||||
                <div v-if="form.errors.has('contacts.'+error_index+'.last_name')" class="text-danger" v-text="form.errors.get('contacts.'+error_index+'.last_name')"></div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group row">
 | 
			
		||||
            <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.email') }}</label>
 | 
			
		||||
            <div class="col-sm-9">
 | 
			
		||||
                <input type="email" :placeholder="trans('texts.email')" v-model="contact.email" class="form-control">
 | 
			
		||||
                <div v-if="form.errors.has('contacts.'+error_index+'.email')" class="text-danger" v-text="form.errors.get('contacts.'+error_index+'.email')"></div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group row">
 | 
			
		||||
            <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.phone') }}</label>
 | 
			
		||||
            <div class="col-sm-9">
 | 
			
		||||
                <input type="text" :placeholder="trans('texts.phone')" v-model="contact.phone" class="form-control">
 | 
			
		||||
                <div v-if="form.errors.has('contacts.'+error_index+'.phone')" class="text-danger" v-text="form.errors.get('contacts.'+error_index+'.phone')"></div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group row" v-if="!!company.settings.custom_client_contact_label1">
 | 
			
		||||
            <label for="name" class="col-sm-3 col-form-label text-right">{{ company.settings.custom_client_contact_label1 }}</label>
 | 
			
		||||
            <div class="col-sm-9">
 | 
			
		||||
                <input type="text" :placeholder="trans('texts.custom_value1')" v-model="contact.custom_value1" class="form-control">
 | 
			
		||||
                <div v-if="form.errors.has('contacts.'+error_index+'.custom_value1')" class="text-danger" v-text="form.errors.get('contacts.'+error_index+'.custom_value1')"></div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group row" v-if="!!company.settings.custom_client_contact_label2">
 | 
			
		||||
            <label for="name" class="col-sm-3 col-form-label text-right">{{ company.settings.custom_client_contact_label2 }}</label>
 | 
			
		||||
            <div class="col-sm-9">
 | 
			
		||||
                <input type="text" :placeholder="trans('texts.custom_value1')" v-model="contact.custom_value2" class="form-control">
 | 
			
		||||
                <div v-if="form.errors.has('contacts.'+error_index+'.custom_value2')" class="text-danger" v-text="form.errors.get('contacts.'+error_index+'.custom_value2')"></div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group row" v-if="!!company.settings.custom_client_contact_label3">
 | 
			
		||||
            <label for="name" class="col-sm-3 col-form-label text-right">{{ company.settings.custom_client_contact_label3 }}</label>
 | 
			
		||||
            <div class="col-sm-9">
 | 
			
		||||
                <input type="text" :placeholder="trans('texts.custom_value1')" v-model="contact.custom_value3" class="form-control">
 | 
			
		||||
                <div v-if="form.errors.has('contacts.'+error_index+'.custom_value3')" class="text-danger" v-text="form.errors.get('contacts.'+error_index+'.custom_value3')"></div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group row" v-if="!!company.settings.custom_client_contact_label4">
 | 
			
		||||
            <label for="name" class="col-sm-3 col-form-label text-right">{{ company.settings.custom_client_contact_label4 }}</label>
 | 
			
		||||
            <div class="col-sm-9">
 | 
			
		||||
                <input type="text" :placeholder="trans('texts.custom_value1')" v-model="contact.custom_value4" class="form-control">
 | 
			
		||||
                <div v-if="form.errors.has('contacts.'+error_index+'.custom_value4')" class="text-danger" v-text="form.errors.get('contacts.'+error_index+'.custom_value4')"></div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="float-right">
 | 
			
		||||
            <button type="button" class="btn btn-danger" v-on:click="$emit('remove',contact)"> {{ trans('texts.remove_contact') }}</button>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    export default {
 | 
			
		||||
        props: ['company', 'contact', 'form', 'error_index']
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
@ -1,72 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="card-body">
 | 
			
		||||
    <div class="form-group row">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.client_name') }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" :placeholder="trans('texts.client_name')" v-model="client.name" class="form-control">
 | 
			
		||||
                 <div v-if="client.errors.has('name')" class="text-danger" v-text="client.errors.get('name')"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="form-group row">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.id_number') }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" name="id_number" :placeholder="trans('texts.id_number')" v-model="client.id_number" class="form-control" id="id_number">
 | 
			
		||||
            <div v-if="client.errors.has('id_number')" class="text-danger" v-text="client.errors.get('id_number')"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="form-group row">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.vat_number') }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" name="vat_number" :placeholder="trans('texts.vat_number')" v-model="client.vat_number" class="form-control" id="vat_number">
 | 
			
		||||
            <div v-if="client.errors.has('vat_number')" class="text-danger" v-text="client.errors.get('vat_number')"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="form-group row">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.website') }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" name="website" :placeholder="trans('texts.website')" v-model="client.website" class="form-control" id="websites">
 | 
			
		||||
            <div v-if="client.errors.has('website')" class="text-danger" v-text="client.errors.get('website')"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="form-group row" v-if="company.custom_client_label1 && company.custom_client_label1.length >= 1">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ company.custom_client_label1 }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" name="custom_value1" :placeholder="trans('texts.custom_value1')" v-model="client.custom_value1" class="form-control" id="custom_value1">
 | 
			
		||||
            <div v-if="client.errors.has('custom_value1')" class="text-danger" v-text="client.errors.get('custom_value1')"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="form-group row" v-if="company.custom_client_label2 && company.custom_client_label2.length >= 1">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ company.custom_client_label2 }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" name="custom_value2" :placeholder="trans('texts.custom_value1')" v-model="client.custom_value2" class="form-control" id="custom_value2">
 | 
			
		||||
            <div v-if="client.errors.has('custom_value2')" class="text-danger" v-text="client.errors.get('custom_value2')"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="form-group row" v-if="company.custom_client_label3 && company.custom_client_label3.length >= 1">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ company.custom_client_label3 }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" name="custom_value3" :placeholder="trans('texts.custom_value1')" v-model="client.custom_value3" class="form-control" id="custom_value3">
 | 
			
		||||
            <div v-if="client.errors.has('custom_value3')" class="text-danger" v-text="client.errors.get('custom_value2')"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="form-group row" v-if="company.custom_client_label4 && company.custom_client_label4.length >= 1">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ company.custom_client_label2 }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" name="custom_value4" :placeholder="trans('texts.custom_value1')" v-model="client.custom_value4" class="form-control" id="custom_value4">
 | 
			
		||||
            <div v-if="client.errors.has('custom_value4')" class="text-danger" v-text="client.errors.get('custom_value4')"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
<script>
 | 
			
		||||
    export default {
 | 
			
		||||
        props: ['client','errors', 'company']
 | 
			
		||||
    }
 | 
			
		||||
</script>	
 | 
			
		||||
@ -1,118 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <form @submit.prevent="onSubmit" @keydown="form.errors.clear($event.target.name)">
 | 
			
		||||
        
 | 
			
		||||
            <div class="row">
 | 
			
		||||
                <!-- Client Details and Address Column -->
 | 
			
		||||
                <div class="col-md-6">
 | 
			
		||||
                    <div class="card">
 | 
			
		||||
                        <div class="card-header bg-primary2">{{ trans('texts.edit_client') }}</div>
 | 
			
		||||
                            <client-edit :client="form" :company="company"></client-edit>
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                    <div class="card">
 | 
			
		||||
                        <div class="card-header bg-primary2">{{ trans('texts.address') }}</div>
 | 
			
		||||
                            <client-address v-bind:client="form" @copy="copy" :countries="countries"></client-address>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <!-- End Client Details and Address Column -->
 | 
			
		||||
 | 
			
		||||
                <!-- Contact Details Column -->
 | 
			
		||||
                <div class="col-md-6">
 | 
			
		||||
                    <div class="card">
 | 
			
		||||
                        <div class="card-header bg-primary2">{{ trans('texts.contact_information') }}
 | 
			
		||||
                            <span class="float-right">
 | 
			
		||||
                                <button type="button" class="btn btn-primary btn-sm" @click="add"><i class="fa fa-plus-circle"></i> {{ trans('texts.add_contact') }}</button>
 | 
			
		||||
                            </span>
 | 
			
		||||
                        </div>
 | 
			
		||||
                            <contact-edit   v-for="(contact, key, index) in form.contacts" 
 | 
			
		||||
                                            :contact="contact" 
 | 
			
		||||
                                            :form="form"
 | 
			
		||||
                                            :key="contact.id"
 | 
			
		||||
                                            :error_index="key"
 | 
			
		||||
                                            :company="company"
 | 
			
		||||
                                            @remove="remove"></contact-edit>
 | 
			
		||||
                    </div>    
 | 
			
		||||
                </div>     
 | 
			
		||||
                <!-- End Contact Details Column --> 
 | 
			
		||||
            </div>     
 | 
			
		||||
 | 
			
		||||
            <div class="row"> 
 | 
			
		||||
 | 
			
		||||
                <div class="col-md-12 text-center">
 | 
			
		||||
 | 
			
		||||
                    <button class="btn btn-lg btn-success" type="button" @click="onSubmit"><i class="fa fa-save"></i> {{ trans('texts.save') }}</button>
 | 
			
		||||
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
            </div>   
 | 
			
		||||
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
 | 
			
		||||
import Form from '../../utils/form';
 | 
			
		||||
import Client from '../../models/client-model';
 | 
			
		||||
import Vue from 'vue'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    data: function () {
 | 
			
		||||
        return {
 | 
			
		||||
            form: new Form(<Client>this.clientdata)
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    props: ['hashed_id', 'clientdata', 'countries', 'company'],
 | 
			
		||||
    beforeMount: function () {
 | 
			
		||||
    },
 | 
			
		||||
    methods:{
 | 
			
		||||
        remove(this:any, contact:any){
 | 
			
		||||
            let index = this.form.contacts.indexOf(contact);
 | 
			
		||||
            this.form.contacts.splice(index, 1);
 | 
			
		||||
        },
 | 
			
		||||
        add(this: any){
 | 
			
		||||
            this.form.contacts.push({first_name: '', last_name: '', email: '', phone: '', id: 0});
 | 
			
		||||
            window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight);
 | 
			
		||||
            this.$nextTick(() => {
 | 
			
		||||
                     let index = this.form.contacts.length - 1;
 | 
			
		||||
                     //this.$refs.first_name[index].$el.focus();
 | 
			
		||||
                     //this.$refs.first_name[index].focus();
 | 
			
		||||
                  });
 | 
			
		||||
        },
 | 
			
		||||
        onSubmit() {
 | 
			
		||||
            this.form.put('/clients/' + this.hashed_id)
 | 
			
		||||
                .then(response => this.$root.$refs.toastr.s( Vue.prototype.trans('texts.updated_client') ))
 | 
			
		||||
                .catch(error => {
 | 
			
		||||
 | 
			
		||||
                    this.$root.$refs.toastr.e("Error saving client");
 | 
			
		||||
 | 
			
		||||
                });
 | 
			
		||||
        },
 | 
			
		||||
        copy(type: any) {
 | 
			
		||||
            if(type.includes('copy_billing')){
 | 
			
		||||
                this.form.shipping_address1 = this.form.address1; 
 | 
			
		||||
                this.form.shipping_address2 = this.form.address2; 
 | 
			
		||||
                this.form.shipping_city = this.form.city; 
 | 
			
		||||
                this.form.shipping_state = this.form.state; 
 | 
			
		||||
                this.form.shipping_postal_code = this.form.postal_code; 
 | 
			
		||||
                this.form.shipping_country_id = this.form.country_id; 
 | 
			
		||||
                }else {
 | 
			
		||||
                this.form.address1 = this.form.shipping_address1; 
 | 
			
		||||
                this.form.address2 = this.form.shipping_address2; 
 | 
			
		||||
                this.form.city = this.form.shipping_city; 
 | 
			
		||||
                this.form.state = this.form.shipping_state; 
 | 
			
		||||
                this.form.postal_code = this.form.shipping_postal_code; 
 | 
			
		||||
                this.form.country_id = this.form.shipping_country_id; 
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    created:function() {
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
    },
 | 
			
		||||
    updated:function() {
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
@ -1,23 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div>		      
 | 
			
		||||
		<vuetable-filter-bar></vuetable-filter-bar>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
 | 
			
		||||
import Vue from 'vue'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
 | 
			
		||||
mounted() {
 | 
			
		||||
	
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style type="text/css">
 | 
			
		||||
	
 | 
			
		||||
</style>
 | 
			
		||||
@ -1,181 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
 | 
			
		||||
	<div>
 | 
			
		||||
 | 
			
		||||
      <vuetable ref="vuetable"
 | 
			
		||||
	      api-url="/clients"
 | 
			
		||||
	      :fields="fields"
 | 
			
		||||
      	:per-page="perPage"
 | 
			
		||||
      	:sort-order="sortOrder"
 | 
			
		||||
      	:append-params="moreParams"
 | 
			
		||||
        :css="css.table"
 | 
			
		||||
  		  pagination-path=""
 | 
			
		||||
        @vuetable:checkbox-toggled="toggledCheckBox()"
 | 
			
		||||
        @vuetable:checkbox-toggled-all="toggledCheckBox()"
 | 
			
		||||
      	@vuetable:pagination-data="onPaginationData"></vuetable>
 | 
			
		||||
 | 
			
		||||
  		<div class="vuetable-pagination ui basic segment grid">
 | 
			
		||||
 | 
			
		||||
        	<vuetable-pagination-info ref="paginationInfo"></vuetable-pagination-info>
 | 
			
		||||
 | 
			
		||||
        	<vuetable-pagination ref="pagination"
 | 
			
		||||
        	:css="css.pagination"
 | 
			
		||||
        	@vuetable-pagination:change-page="onChangePage"></vuetable-pagination>
 | 
			
		||||
 | 
			
		||||
    	</div>
 | 
			
		||||
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
 | 
			
		||||
import Vuetable from 'vuetable-2/src/components/Vuetable.vue'
 | 
			
		||||
import VuetablePagination from 'vuetable-2/src/components/VuetablePagination.vue'
 | 
			
		||||
import VuetablePaginationInfo from 'vuetable-2/src/components/VuetablePaginationInfo.vue'
 | 
			
		||||
import Vue from 'vue'
 | 
			
		||||
import VueEvents from 'vue-events'
 | 
			
		||||
import VuetableCss from '../util/VuetableCss'
 | 
			
		||||
import axios from 'axios'
 | 
			
		||||
 | 
			
		||||
Vue.use(VueEvents)
 | 
			
		||||
 | 
			
		||||
declare var bulk_count : number;
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
 | 
			
		||||
	components: {
 | 
			
		||||
        	Vuetable,
 | 
			
		||||
	      	VuetablePagination,
 | 
			
		||||
	      	VuetablePaginationInfo
 | 
			
		||||
	},
 | 
			
		||||
  data: function () {
 | 
			
		||||
      return {
 | 
			
		||||
          css: VuetableCss,
 | 
			
		||||
          perPage: this.datatable.per_page,
 | 
			
		||||
          sortOrder: this.datatable.sort_order,
 | 
			
		||||
          moreParams: this.$store.getters['client_list/getQueryStringObject'],
 | 
			
		||||
          fields: this.datatable.fields
 | 
			
		||||
      }
 | 
			
		||||
  },
 | 
			
		||||
  props: ['datatable'],
 | 
			
		||||
  mounted() {
 | 
			
		||||
 | 
			
		||||
    this.$events.$on('filter-set', eventData => this.onFilterSet())
 | 
			
		||||
    this.$events.$on('bulk-action', eventData => this.bulkAction(eventData))
 | 
			
		||||
    this.$events.$on('multi-select', eventData => this.multiSelect(eventData))
 | 
			
		||||
    this.$events.$on('single-action', eventData => this.singleAction(eventData))
 | 
			
		||||
    this.$events.$on('perpage_action', eventData => this.onPerPageUpdate(eventData))
 | 
			
		||||
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
 | 
			
		||||
    onPaginationData (paginationData : any) {
 | 
			
		||||
 | 
			
		||||
      this.$refs.pagination.setPaginationData(paginationData)
 | 
			
		||||
      this.$refs.paginationInfo.setPaginationData(paginationData) 
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
    onChangePage (page : any) {
 | 
			
		||||
 | 
			
		||||
		this.$refs.vuetable.changePage(page)
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
	  onFilterSet () {
 | 
			
		||||
 | 
			
		||||
      this.moreParams = this.$store.getters['client_list/getQueryStringObject']
 | 
			
		||||
			Vue.nextTick( () => this.$refs.vuetable.refresh())
 | 
			
		||||
 | 
			
		||||
	  },
 | 
			
		||||
    onPerPageUpdate(per_page){
 | 
			
		||||
 | 
			
		||||
      this.perPage = Number(per_page)
 | 
			
		||||
      Vue.nextTick( () => this.$refs.vuetable.refresh())
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
    bulkAction (action){
 | 
			
		||||
 | 
			
		||||
      var dataObj = {
 | 
			
		||||
        'action' : action,
 | 
			
		||||
        'ids' : this.$refs.vuetable.selectedTo
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.postBulkAction(dataObj)
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
    singleAction(dataObj) {
 | 
			
		||||
 | 
			
		||||
      this.postBulkAction(dataObj)
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
    postBulkAction(dataObj) {
 | 
			
		||||
 | 
			
		||||
      axios.post('/clients/bulk', dataObj)
 | 
			
		||||
      .then((response) => {
 | 
			
		||||
        this.$root.$refs.toastr.s( Vue.prototype.trans('texts.'+dataObj.action+'d_client') )
 | 
			
		||||
        this.$store.commit('client_list/setBulkCount', 0)
 | 
			
		||||
        this.$refs.vuetable.selectedTo = []
 | 
			
		||||
        this.$refs.vuetable.refresh()
 | 
			
		||||
//        console.dir(response)
 | 
			
		||||
      })
 | 
			
		||||
      .catch(function (error) {
 | 
			
		||||
        this.$root.$refs.toastr.e( "A error occurred" )
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
    toggledCheckBox(){
 | 
			
		||||
      this.$store.commit('client_list/setBulkCount', this.$refs.vuetable.selectedTo.length)
 | 
			
		||||
    },
 | 
			
		||||
    multiSelect(value)
 | 
			
		||||
    {
 | 
			
		||||
      this.moreParams = this.$store.getters['client_list/getQueryStringObject']
 | 
			
		||||
      Vue.nextTick( () => this.$refs.vuetable.refresh())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style type="text/css">
 | 
			
		||||
 | 
			
		||||
  .pagination {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    float: right;
 | 
			
		||||
  }
 | 
			
		||||
  .pagination a.page {
 | 
			
		||||
    border: 1px solid lightgray;
 | 
			
		||||
    border-radius: 3px;
 | 
			
		||||
    padding: 5px 10px;
 | 
			
		||||
    margin-right: 2px;
 | 
			
		||||
  }
 | 
			
		||||
  .pagination a.page.active {
 | 
			
		||||
    color: white;
 | 
			
		||||
    background-color: #337ab7;
 | 
			
		||||
    border: 1px solid lightgray;
 | 
			
		||||
    border-radius: 3px;
 | 
			
		||||
    padding: 5px 10px;
 | 
			
		||||
    margin-right: 2px;
 | 
			
		||||
  }
 | 
			
		||||
  .pagination a.btn-nav {
 | 
			
		||||
    border: 1px solid lightgray;
 | 
			
		||||
    border-radius: 3px;
 | 
			
		||||
    padding: 5px 7px;
 | 
			
		||||
    margin-right: 2px;
 | 
			
		||||
  }
 | 
			
		||||
  .pagination a.btn-nav.disabled {
 | 
			
		||||
    color: lightgray;
 | 
			
		||||
    border: 1px solid lightgray;
 | 
			
		||||
    border-radius: 3px;
 | 
			
		||||
    padding: 5px 7px;
 | 
			
		||||
    margin-right: 2px;
 | 
			
		||||
    cursor: not-allowed;
 | 
			
		||||
  }
 | 
			
		||||
  .pagination-info {
 | 
			
		||||
    float: left;
 | 
			
		||||
  }
 | 
			
		||||
  th {
 | 
			
		||||
    background: #777777;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@ -1,421 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
 | 
			
		||||
<div class="row" style="background:#fff; padding:20px;">
 | 
			
		||||
 | 
			
		||||
	<div class="col-2" style="border: 0px; border-style:solid;">
 | 
			
		||||
 | 
			
		||||
		<affix class="menu sidebar-menu" relative-element-selector="#example-content" :offset="{ top: 50, bottom:100 }" :scroll-affix="false" style="width: 200px">
 | 
			
		||||
          <div class="menu-label">
 | 
			
		||||
            <h3 style="color:#5d5d5d;">{{ trans('texts.settings') }}</h3>
 | 
			
		||||
          </div>
 | 
			
		||||
          <scrollactive 
 | 
			
		||||
          	class="menu-list" 
 | 
			
		||||
          	active-class="is-active"
 | 
			
		||||
          	:offset="50"
 | 
			
		||||
		  	:duration="800"
 | 
			
		||||
          	:exact="true"
 | 
			
		||||
          	>
 | 
			
		||||
          	<ul class="list-inline justify-content-left">
 | 
			
		||||
                <li class="menu-li"><a href="#intro" class="scrollactive-item" >{{trans('t.client_settings')}}</a></li>
 | 
			
		||||
                <li class="menu-li"><a href="#standard-affix" class="scrollactive-item" >{{trans('texts.messages')}}</a></li>
 | 
			
		||||
                <li class="menu-li"><a href="#scroll-affix" class="scrollactive-item" >{{trans('texts.classify')}}</a></li>
 | 
			
		||||
        	</ul>
 | 
			
		||||
          </scrollactive>
 | 
			
		||||
        </affix>
 | 
			
		||||
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<div class="col-10">
 | 
			
		||||
 | 
			
		||||
		<div id="example-content">
 | 
			
		||||
 | 
			
		||||
          <section id="intro">
 | 
			
		||||
                <div class="card">
 | 
			
		||||
                    <div class="card-header bg-primary2">{{ trans('t.client_settings') }}</div>
 | 
			
		||||
                        <div class="card-body px-3">
 | 
			
		||||
						    <div class="form-group row client_form">
 | 
			
		||||
						        <label for="name" class="col-sm-5 text-left">
 | 
			
		||||
						        	<div>{{ trans('texts.currency') }}</div>
 | 
			
		||||
									<div style="margin-top:1px; line-height:1.4; color:#939393;">{{ trans('help.client_currency') }}</div>
 | 
			
		||||
						        </label>
 | 
			
		||||
						        <div class="col-sm-7">
 | 
			
		||||
						            <multiselect v-model="settings.currency_id" :options="options_currency" label="name" track-by="id" :allow-empty="true" @select="currencySettingChange()"></multiselect>
 | 
			
		||||
						        </div>
 | 
			
		||||
						    </div>
 | 
			
		||||
						    <div class="form-group row client_form d-flex justify-content-center">
 | 
			
		||||
								<div class="form-check form-check-inline">
 | 
			
		||||
									<input class="form-check-input" id="inline-radio1" type="radio" name="symbol" value="1" v-model="settings.show_currency_symbol" @click="setCurrencySymbol()">
 | 
			
		||||
									<label class="form-check-label" for="show_currency_symbol-radio1">{{ trans('texts.currency_symbol') }}: {{ currency_symbol_example }}</label>
 | 
			
		||||
								</div>
 | 
			
		||||
								<div class="form-check form-check-inline">
 | 
			
		||||
									<input class="form-check-input" id="inline-radio2" type="radio" name="code" value="1" v-model="settings.show_currency_code" @click="setCurrencyCode()">
 | 
			
		||||
									<label class="form-check-label" for="show_currency_code">{{ trans('texts.currency_code') }}: {{ currency_code_example }}</label>
 | 
			
		||||
								</div>
 | 
			
		||||
							</div>
 | 
			
		||||
						    <div class="form-group row client_form">
 | 
			
		||||
						        <label for="language" class="col-sm-5 text-left">
 | 
			
		||||
						        	<div>{{ trans('texts.language') }}</div>
 | 
			
		||||
									<div style="margin-top:1px; line-height:1.4; color:#939393;">{{ trans('help.client_language')}}</div>
 | 
			
		||||
						        </label>
 | 
			
		||||
						        <div class="col-sm-7">
 | 
			
		||||
						            <multiselect v-model="settings.language_id" :options="options_language" :placeholder="placeHolderLanguage()" label="name" track-by="id" :allow-empty="true"></multiselect>
 | 
			
		||||
						        </div>
 | 
			
		||||
						    </div>
 | 
			
		||||
						    <div class="form-group row client_form">
 | 
			
		||||
						        <label for="payment_terms" class="col-sm-5 text-left">
 | 
			
		||||
						        	<div>{{ trans('texts.payment_terms') }}</div>
 | 
			
		||||
									<div style="margin-top:1px; line-height:1.4; color:#939393;">{{ trans('help.client_payment_terms')}}</div>
 | 
			
		||||
						        </label>
 | 
			
		||||
						        <div class="col-sm-7">
 | 
			
		||||
						            <multiselect v-model="settings.payment_terms" :options="options_payment_term" :placeholder="placeHolderPaymentTerm()" label="name" track-by="num_days" :allow-empty="true"></multiselect>
 | 
			
		||||
						        </div>
 | 
			
		||||
						    </div>
 | 
			
		||||
						    
 | 
			
		||||
						    <div class="form-group row client_form">
 | 
			
		||||
						        <label for="name" class="col-sm-5 col-form-label text-left">
 | 
			
		||||
						        <div>{{ trans('texts.task_rate') }}</div>
 | 
			
		||||
								<div style="margin-top:1px; line-height:1.4; color:#939393;">{{ trans('texts.task_rate_help')}}</div>
 | 
			
		||||
						    	</label>
 | 
			
		||||
						        <div class="col-sm-7">
 | 
			
		||||
						            <input type="text" :placeholder="trans('texts.task_rate')" class="form-control" v-model="settings.task_rate">
 | 
			
		||||
						                 <div v-if="" class="text-danger" v-text=""></div>
 | 
			
		||||
						        </div>
 | 
			
		||||
						    </div>
 | 
			
		||||
						    <div class="form-group row client_form">
 | 
			
		||||
						        <label for="name" class="col-sm-5 col-form-label text-left">{{ trans('texts.send_client_reminders') }}</label>
 | 
			
		||||
						        <div class="col-sm-7">
 | 
			
		||||
						            <label class="switch switch-label switch-pill switch-info">
 | 
			
		||||
									<input class="switch-input" type="checkbox" checked="" v-model="settings.send_reminders">
 | 
			
		||||
									<span class="switch-slider" data-checked="✓" data-unchecked="✕"></span>
 | 
			
		||||
									</label>
 | 
			
		||||
						        </div>
 | 
			
		||||
						    </div>
 | 
			
		||||
						    <div class="form-group row client_form">
 | 
			
		||||
						        <label for="name" class="col-sm-5 col-form-label text-left">{{ trans('texts.show_tasks_in_portal') }}</label>
 | 
			
		||||
						        <div class="col-sm-7">
 | 
			
		||||
						            <label class="switch switch-label switch-pill switch-info">
 | 
			
		||||
									<input class="switch-input" type="checkbox" checked="" v-model="settings.show_tasks_in_portal">
 | 
			
		||||
									<span class="switch-slider" data-checked="✓" data-unchecked="✕"></span>
 | 
			
		||||
									</label>
 | 
			
		||||
						        </div>
 | 
			
		||||
						    </div>
 | 
			
		||||
 | 
			
		||||
						</div>
 | 
			
		||||
					
 | 
			
		||||
                </div>
 | 
			
		||||
          </section>
 | 
			
		||||
 | 
			
		||||
          <section id="standard-affix">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                    <div class="card-header bg-primary2">{{ trans('texts.messages') }}</div>
 | 
			
		||||
                        <div class="card-body">
 | 
			
		||||
						    <div class="form-group row client_form">
 | 
			
		||||
						        <label for="name" class="col-sm-5 col-form-label text-left">
 | 
			
		||||
						        	<div>{{ trans('texts.dashboard') }}</div>
 | 
			
		||||
									<div style="margin-top:1px; line-height:1.4; color:#939393;">{{ trans('help.client_dashboard')}}</div>
 | 
			
		||||
						    	</label>
 | 
			
		||||
						        <div class="col-sm-7">
 | 
			
		||||
						            <textarea class="form-control" id="textarea-input" label="dashboard" v-model="settings.custom_message_dashboard"rows="9" :placeholder="placeHolderMessage('custom_message_dashboard')"></textarea>
 | 
			
		||||
						        </div>
 | 
			
		||||
						    </div>
 | 
			
		||||
						    <div class="form-group row client_form">
 | 
			
		||||
						        <label for="name" class="col-sm-5 col-form-label text-left">
 | 
			
		||||
						        	<div>{{ trans('texts.unpaid_invoice') }}</div>
 | 
			
		||||
									<div style="margin-top:1px; line-height:1.4; color:#939393;">{{ trans('help.client_unpaid_invoice')}}</div>
 | 
			
		||||
								</label>
 | 
			
		||||
						        <div class="col-sm-7">
 | 
			
		||||
						            <textarea class="form-control" id="textarea-input" label="unpaid_invoice" v-model="settings.custom_message_unpaid_invoice"rows="9" :placeholder="placeHolderMessage('custom_message_unpaid_invoice')"></textarea>
 | 
			
		||||
						        </div>
 | 
			
		||||
						    </div>
 | 
			
		||||
						    <div class="form-group row client_form">
 | 
			
		||||
						        <label for="name" class="col-sm-5 col-form-label text-left">
 | 
			
		||||
						        	<div>{{ trans('texts.paid_invoice') }}</div>
 | 
			
		||||
									<div style="margin-top:1px; line-height:1.4; color:#939393;">{{trans('help.client_paid_invoice')}}</div>
 | 
			
		||||
								</label>
 | 
			
		||||
						        <div class="col-sm-7">
 | 
			
		||||
						            <textarea class="form-control" id="textarea-input" label="paid_invoice"  v-model="settings.custom_message_paid_invoice" rows="9" :placeholder="placeHolderMessage('custom_message_paid_invoice')"></textarea>
 | 
			
		||||
						        </div>
 | 
			
		||||
						    </div>
 | 
			
		||||
						    <div class="form-group row client_form">
 | 
			
		||||
								<label class="col-sm-5 col-form-label text-left" for="unapproved_quote">
 | 
			
		||||
									<div>{{ trans('texts.unapproved_quote') }}</div>
 | 
			
		||||
									<div style="margin-top:1px; line-height:1.4; color:#939393;">{{trans('help.client_unapproved_quote')}}</div>
 | 
			
		||||
								</label>
 | 
			
		||||
								<div class="col-md-7">
 | 
			
		||||
									<textarea class="form-control" id="textarea-input" label="unapproved_quote" v-model="settings.custom_message_unapproved_quote" rows="9" :placeholder="placeHolderMessage('custom_message_unapproved_quote')"></textarea>
 | 
			
		||||
								</div>
 | 
			
		||||
							</div>
 | 
			
		||||
 | 
			
		||||
						</div>
 | 
			
		||||
					
 | 
			
		||||
                </div>
 | 
			
		||||
          </section>
 | 
			
		||||
 | 
			
		||||
          <section id="scroll-affix">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                    <div class="card-header bg-primary2">{{ trans('texts.classify') }}</div>
 | 
			
		||||
                        <div class="card-body">
 | 
			
		||||
						    <div class="form-group row client_form">
 | 
			
		||||
						        <label for="name" class="col-sm-5 col-form-label text-left">{{ trans('texts.industry') }}</label>
 | 
			
		||||
						        <div class="col-sm-7">
 | 
			
		||||
						            <multiselect :options="options_industry" :placeholder="placeHolderIndustry()" label="name" track-by="id" v-model="settings.industry_id"></multiselect>
 | 
			
		||||
						        </div>
 | 
			
		||||
						    </div>
 | 
			
		||||
						    <div class="form-group row client_form">
 | 
			
		||||
						        <label for="name" class="col-sm-5 col-form-label text-left">{{ trans('texts.size_id') }}</label>
 | 
			
		||||
						        <div class="col-sm-7">
 | 
			
		||||
						            <multiselect :options="options_size" :placeholder="placeHolderSize()" label="name" track-by="id" v-model="settings.size_id"></multiselect>
 | 
			
		||||
						        </div>
 | 
			
		||||
						    </div>
 | 
			
		||||
 | 
			
		||||
						</div>
 | 
			
		||||
					
 | 
			
		||||
                </div>
 | 
			
		||||
          </section>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
        		
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
 | 
			
		||||
import Vue from 'vue'
 | 
			
		||||
import { Affix } from 'vue-affix'
 | 
			
		||||
var VueScrollactive = require('vue-scrollactive')
 | 
			
		||||
import NumberFormat from '../../utils/number-format'
 | 
			
		||||
import Multiselect from 'vue-multiselect'
 | 
			
		||||
import ClientSettings from '../../utils/client-settings'
 | 
			
		||||
 | 
			
		||||
Vue.use(VueScrollactive);
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
	components: {
 | 
			
		||||
		Affix,
 | 
			
		||||
	    Multiselect,
 | 
			
		||||
	},
 | 
			
		||||
	data () {
 | 
			
		||||
	    return {
 | 
			
		||||
			options_currency: Object.keys(this.currencies).map(i => this.currencies[i]),
 | 
			
		||||
			options_language: Object.keys(this.languages).map(i => this.languages[i]),
 | 
			
		||||
			options_payment_term: Object.keys(this.payment_terms).map(i => this.payment_terms[i]),
 | 
			
		||||
			options_industry: Object.keys(this.industries).map(i => this.industries[i]),
 | 
			
		||||
			options_size: this.sizes,
 | 
			
		||||
			settings: this.client_settings
 | 
			
		||||
	    }
 | 
			
		||||
	  },
 | 
			
		||||
    props: ['client_settings', 'currencies', 'languages', 'payment_terms', 'industries', 'sizes', 'company'],
 | 
			
		||||
    mounted() {
 | 
			
		||||
 | 
			
		||||
    	//console.dir(this.settings)
 | 
			
		||||
		this.updateCurrencyExample()
 | 
			
		||||
	},
 | 
			
		||||
    computed: {
 | 
			
		||||
		currency_code_example: {
 | 
			
		||||
			get: function() {
 | 
			
		||||
				return this.updateCurrencyExample(false)
 | 
			
		||||
			},
 | 
			
		||||
			set: function() {
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		currency_symbol_example: {
 | 
			
		||||
			get: function() {
 | 
			
		||||
				return this.updateCurrencyExample(true)
 | 
			
		||||
			},
 | 
			
		||||
			set: function() {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
		setObjectValue(key, value){
 | 
			
		||||
 | 
			
		||||
			if(value === null)
 | 
			
		||||
				this.settings[key] = null
 | 
			
		||||
			else
 | 
			
		||||
				this.settings[key] = value
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
		placeHolderCurrency(){
 | 
			
		||||
 | 
			
		||||
			var currency = this.options_currency.find(obj => {
 | 
			
		||||
				return obj.id == this.company.settings_object.currency_id
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			if(currency)
 | 
			
		||||
				return currency.name
 | 
			
		||||
			else
 | 
			
		||||
				return  Vue.prototype.trans('texts.currency_id') 	
 | 
			
		||||
 | 
			
		||||
		},		
 | 
			
		||||
		placeHolderPaymentTerm(){
 | 
			
		||||
 | 
			
		||||
			var payment_terms = this.payment_terms.find(obj => {
 | 
			
		||||
			  return obj.num_days == this.company.settings_object.payment_terms
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			if(payment_terms)
 | 
			
		||||
				return payment_terms.name
 | 
			
		||||
			else
 | 
			
		||||
				return  Vue.prototype.trans('texts.payment_terms') 	
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
		placeHolderIndustry(){
 | 
			
		||||
 | 
			
		||||
			return  Vue.prototype.trans('texts.industry_id') 
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
		placeHolderSize(){
 | 
			
		||||
 | 
			
		||||
			return  Vue.prototype.trans('texts.size_id') 	
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
		placeHolderLanguage(){
 | 
			
		||||
 | 
			
		||||
			var language = this.languages.find(obj => {
 | 
			
		||||
			  return obj.id == this.company.settings_object.language_id
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			if(language)
 | 
			
		||||
				return language.name
 | 
			
		||||
			else
 | 
			
		||||
				return  Vue.prototype.trans('texts.language_id') 
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
		placeHolderMessage(message_setting : string) {
 | 
			
		||||
 | 
			
		||||
			if(this.company.settings_object[message_setting] && this.company.settings_object[message_setting].length >=1) {
 | 
			
		||||
 | 
			
		||||
				return this.company.settings_object[message_setting]
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
		setCurrencyCode() {
 | 
			
		||||
			this.settings.show_currency_symbol = false;
 | 
			
		||||
			this.settings.show_currency_code = true;
 | 
			
		||||
 | 
			
		||||
			this.currencySettingChange()
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
		setCurrencySymbol() {
 | 
			
		||||
 | 
			
		||||
			this.settings.show_currency_symbol = true;
 | 
			
		||||
			this.settings.show_currency_code = false;
 | 
			
		||||
 | 
			
		||||
			this.currencySettingChange()
 | 
			
		||||
 | 
			
		||||
		},
 | 
			
		||||
		updateCurrencyExample(currency_symbol) {
 | 
			
		||||
 | 
			
		||||
			
 | 
			
		||||
			var currency = this.options_currency.find(obj => {
 | 
			
		||||
				return obj.id == this.company.settings_object.currency_id
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			var language = this.languages.find(obj => {
 | 
			
		||||
			  return obj.id == this.company.settings_object.language_id
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			if(this.settings_language_id)
 | 
			
		||||
				language = this.settings_language_id
 | 
			
		||||
 | 
			
		||||
			if(this.settings_currency_id)
 | 
			
		||||
				currency = this.settings_currency_id
 | 
			
		||||
 | 
			
		||||
			return new NumberFormat(1000, currency, currency_symbol, language).format()
 | 
			
		||||
		},
 | 
			
		||||
		currencySettingChange() {
 | 
			
		||||
			this.currency_code_example = this.updateCurrencyExample(false)
 | 
			
		||||
			this.currency_symbol_example = this.updateCurrencyExample(true)
 | 
			
		||||
 | 
			
		||||
			console.dir(this.currency_symbol_example)
 | 
			
		||||
			console.dir(this.currency_code_example)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
 | 
			
		||||
#example-content {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.client_form {
 | 
			
		||||
	border-bottom: 0px;
 | 
			
		||||
	border-bottom-style: solid;
 | 
			
		||||
    border-bottom-color: #167090;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.menu-li {
 | 
			
		||||
	list-style: none;
 | 
			
		||||
  	padding-left:5px;
 | 
			
		||||
  	width:200px;
 | 
			
		||||
  	line-height:1.4;
 | 
			
		||||
  	margin-top:10px;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a.scrollactive-item.is-active  {
 | 
			
		||||
  color: #027093;
 | 
			
		||||
  font-family: helvetica;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  border-left-style: solid;
 | 
			
		||||
  border-left-color: #027093;
 | 
			
		||||
  padding-left:10px;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a.scrollactive-item.is-active:hover {
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
 | 
			
		||||
  color: #027093;
 | 
			
		||||
  padding-left:10px;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a.scrollactive-item.is-active:active {
 | 
			
		||||
  color: #027093;
 | 
			
		||||
  padding-left:10px;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.menu-list a {
 | 
			
		||||
  color: #939393;
 | 
			
		||||
 | 
			
		||||
  font-family: helvetica;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.menu-list a:hover {
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
 | 
			
		||||
  color: #027093;
 | 
			
		||||
  padding-left:5px;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.menu-list a:active {
 | 
			
		||||
  color: #027093;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
      padding-left:5px;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@ -1,181 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
 | 
			
		||||
	<div class="container-fluid">
 | 
			
		||||
 | 
			
		||||
		<div class="row">
 | 
			
		||||
		    <div class="col" style="padding: 0px;">
 | 
			
		||||
		    
 | 
			
		||||
			    <div class="float-right">
 | 
			
		||||
 | 
			
		||||
					<div class="btn-group ml-2">
 | 
			
		||||
				      <button type="button" class="btn btn-lg btn-secondary" :disabled="editClientIsDisabled" v-for="link in this.meta.edit_client_route" @click="goToUrl(link.url)">{{ trans('texts.edit_client') }}</button>
 | 
			
		||||
				      <button type="button" class="btn btn-lg btn-secondary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" :disabled="editClientIsDisabled">
 | 
			
		||||
				        <span class="sr-only">Toggle Dropdown</span>
 | 
			
		||||
				      </button>
 | 
			
		||||
				      <div class="dropdown-menu" x-placement="top-start" style="position: absolute; transform: translate3d(189px, -2px, 0px); top: 0px; left: 0px; will-change: transform;">
 | 
			
		||||
							<a class="dropdown-item" href="#" @click="itemAction('archive', client, rowIndex)" v-if="client.deleted_at == null">{{ trans('texts.archive') }}</a>
 | 
			
		||||
							<a class="dropdown-item" href="#" @click="itemAction('restore', client, rowIndex)" v-if="client.is_deleted == 1 || client.deleted_at != null">{{ trans('texts.restore') }}</a>
 | 
			
		||||
							<a class="dropdown-item" href="#" @click="itemAction('delete', client, rowIndex)" v-if="client.is_deleted == 0">{{ trans('texts.delete') }}</a>
 | 
			
		||||
				        <div class="dropdown-divider"></div>
 | 
			
		||||
				        <a class="dropdown-item" @click="itemAction('purge', client, rowIndex)">{{ trans('texts.purge_client') }}</a>
 | 
			
		||||
				      </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
 | 
			
		||||
					<div class="btn-group ml-2">
 | 
			
		||||
				      <button type="button" class="btn btn-lg btn-primary" :disabled="viewStatementIsDisabled" v-for="link in this.meta.view_statement_route" @click="goToUrl(link.url)">{{ trans('texts.view_statement') }}</button>
 | 
			
		||||
				      <button type="button" class="btn btn-lg btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" :disabled="viewStatementIsDisabled">
 | 
			
		||||
				        <span class="sr-only">Toggle Dropdown</span>
 | 
			
		||||
				      </button>
 | 
			
		||||
				      <div class="dropdown-menu" x-placement="top-start" style="position: absolute; transform: translate3d(189px, -2px, 0px); top: 0px; left: 0px; will-change: transform;">
 | 
			
		||||
				        <a class="dropdown-item" v-for="link in this.meta.view_statement_actions" :href="link.url">{{ link.name }}</a>
 | 
			
		||||
				      </div>
 | 
			
		||||
				    </div>
 | 
			
		||||
 | 
			
		||||
			    </div>
 | 
			
		||||
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
 | 
			
		||||
		<div class="card">
 | 
			
		||||
			<div class="card-body">
 | 
			
		||||
				<div class="row">
 | 
			
		||||
 | 
			
		||||
					<div class="col-sm">
 | 
			
		||||
						<h3> {{ trans('texts.details') }} </h3>
 | 
			
		||||
						<p v-if="client.id_number && client.id_number.length >= 1"><b>{{ trans('texts.id_number') }}:</b> {{ client.id_number }}</p>
 | 
			
		||||
						<p v-if="client.vat_number && client.vat_number.length >= 1"><b>{{ trans('texts.vat_number') }}:</b> {{ client.vat_number }}</p>
 | 
			
		||||
						<p v-if="client.custom_value1 && client.custom_value1.length >= 1"><b>{{ company.custom_client_label1 }}:</b> {{ client.custom_value1 }}</p>
 | 
			
		||||
						<p v-if="client.custom_value2 && client.custom_value2.length >= 1"><b>{{ company.custom_client_label2 }}:</b> {{ client.custom_value2 }}</p>
 | 
			
		||||
						<p v-if="client.custom_value3 && client.custom_value3.length >= 1"><b>{{ company.custom_client_label3 }}:</b> {{ client.custom_value3 }}</p>
 | 
			
		||||
						<p v-if="client.custom_value4 && client.custom_value4.length >= 1"><b>{{ company.custom_client_label4 }}:</b> {{ client.custom_value4 }}</p>
 | 
			
		||||
					</div>
 | 
			
		||||
 | 
			
		||||
					<div class="col-sm">
 | 
			
		||||
						<ul>
 | 
			
		||||
							<li><h3> {{ trans('texts.address') }} </h3></li>
 | 
			
		||||
							<li><b> {{ trans('texts.billing_address') }}</b></li>
 | 
			
		||||
							<li v-if="client.address1 && client.address1.length >=1">{{ client.address1 }} <br></li>
 | 
			
		||||
							<li v-if="client.address2 && client.address2.length >=1">{{ client.address2 }} <br></li>
 | 
			
		||||
							<li v-if="client.city && client.city.length >=1">{{ client.city }} <br></li>
 | 
			
		||||
							<li v-if="client.state && client.state.length >=1" >{{ client.state}} {{client.postal_code}}<br></li>
 | 
			
		||||
							<li v-if="client.country && client.country.name.length >=1">{{ client.country.name }}<br></li>
 | 
			
		||||
						</ul>
 | 
			
		||||
 | 
			
		||||
						<ul v-if="client.shipping_address1 && client.shipping_address1.length >=1">
 | 
			
		||||
							<li><b> {{ trans('texts.shipping_address') }}</b></li>
 | 
			
		||||
							<li v-if="client.shipping_address1 && client.shipping_address1.length >=1">{{ client.shipping_address1 }} <br></li>
 | 
			
		||||
							<li v-if="client.shipping_address2 && client.shipping_address2.length >=1">{{ client.shipping_address2 }} <br></li>
 | 
			
		||||
							<li v-if="client.shipping_city && client.shipping_city.length >=1">{{ client.shipping_city }} <br></li>
 | 
			
		||||
							<li v-if="client.shipping_state && client.shipping_state.length >=1" >{{ client.shipping_state}} {{client.shipping_postal_code}}<br></li>
 | 
			
		||||
							<li v-if="client.shipping_country && client.shipping_country.name.length >=1">{{ client.shipping_country.name }}<br></li>
 | 
			
		||||
						</ul>
 | 
			
		||||
					</div>
 | 
			
		||||
 | 
			
		||||
					<div class="col-sm">
 | 
			
		||||
						<h3> {{ trans('texts.contacts') }} </h3>
 | 
			
		||||
 | 
			
		||||
						<ul v-for="contact in client.contacts"> 
 | 
			
		||||
                        	<li v-if="contact.first_name">{{ contact.first_name }} {{ contact.last_name }}</li>
 | 
			
		||||
                        	<li v-if="contact.email">{{ contact.email }}</li>
 | 
			
		||||
                        	<li v-if="contact.phone">{{ contact.phone }}</li>
 | 
			
		||||
                        	<li v-if="company.custom_client_contact_label1 && company.custom_client_contact_label1.length >= 1"><b>{{ company.custom_client_contact_label1 }}:</b> {{ contact.custom_value1 }}</li>
 | 
			
		||||
							<li v-if="company.custom_client_contact_label2 && company.custom_client_contact_label2.length >= 1"><b>{{ company.custom_client_contact_label2 }}:</b> {{ contact.custom_value2 }}</li>
 | 
			
		||||
							<li v-if="company.custom_client_contact_label3 && company.custom_client_contact_label3.length >= 1"><b>{{ company.custom_client_contact_label3 }}:</b> {{ contact.custom_value3 }}</li>
 | 
			
		||||
							<li v-if="company.custom_client_contact_label4 && company.custom_client_contact_label4.length >= 1"><b>{{ company.custom_client_contact_label4 }}:</b> {{ contact.custom_value4 }}</li>
 | 
			
		||||
                        </ul>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
					</div>
 | 
			
		||||
 | 
			
		||||
					<div class="col-sm">
 | 
			
		||||
						<h3> {{ trans('texts.standing') }} </h3>
 | 
			
		||||
						<p><b>{{ trans('texts.paid_to_date') }} {{client.paid_to_date}}</b></p>
 | 
			
		||||
						<p><b>{{ trans('texts.balance') }} {{client.balance }}</b></p>
 | 
			
		||||
					</div>
 | 
			
		||||
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
		<div v-if="this.meta.google_maps_api_key">
 | 
			
		||||
 | 
			
		||||
		<iframe
 | 
			
		||||
		  width="100%"
 | 
			
		||||
		  height="200px"
 | 
			
		||||
		  frameborder="0" style="border:0"
 | 
			
		||||
		  :src="mapUrl" allowfullscreen>
 | 
			
		||||
		</iframe>
 | 
			
		||||
 | 
			
		||||
		</div>
 | 
			
		||||
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    props: ['client', 'company', 'meta'],
 | 
			
		||||
    mounted() {
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
	methods: {
 | 
			
		||||
		goToUrl(url) {
 | 
			
		||||
			 location.href=url
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
    computed: {
 | 
			
		||||
    	mapUrl: {
 | 
			
		||||
    		get: function() {
 | 
			
		||||
        	  return `https://www.google.com/maps/embed/v1/place?key=${this.meta.google_maps_api_key}&q=${this.clientAddress}`
 | 
			
		||||
		    }
 | 
			
		||||
    	},
 | 
			
		||||
    	clientAddress: {
 | 
			
		||||
    		get: function() {
 | 
			
		||||
 | 
			
		||||
    			var addressArray = []
 | 
			
		||||
 | 
			
		||||
    			if(this.client.address1)
 | 
			
		||||
    				addressArray.push(this.client.address1.split(' ').join('+'))
 | 
			
		||||
 | 
			
		||||
    			if(this.client.address2)
 | 
			
		||||
    				addressArray.push(this.client.address2.split(' ').join('+'))
 | 
			
		||||
 | 
			
		||||
    			if(this.client.city)
 | 
			
		||||
    				addressArray.push(this.client.city.split(' ').join('+'))
 | 
			
		||||
 | 
			
		||||
    			if(this.client.state)
 | 
			
		||||
    				addressArray.push(this.client.state.split(' ').join('+'))
 | 
			
		||||
 | 
			
		||||
    			if(this.client.postal_code)
 | 
			
		||||
    				addressArray.push(this.client.postal_code.split(' ').join('+'))
 | 
			
		||||
 | 
			
		||||
    			if(this.client.country.name)
 | 
			
		||||
    				addressArray.push(this.client.country.name.split(' ').join('+'))
 | 
			
		||||
 | 
			
		||||
    			return encodeURIComponent(addressArray.join(",")) 
 | 
			
		||||
    		}
 | 
			
		||||
    	},
 | 
			
		||||
		viewStatementIsDisabled() :any
 | 
			
		||||
		{
 | 
			
		||||
			return ! this.meta.view_statement_permission
 | 
			
		||||
		},
 | 
			
		||||
		editClientIsDisabled() :any
 | 
			
		||||
		{
 | 
			
		||||
			return ! this.meta.edit_client_permission
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
.card { margin-top:50px; }
 | 
			
		||||
 | 
			
		||||
li { list-style: none }
 | 
			
		||||
</style>
 | 
			
		||||
@ -1,58 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="card-body">
 | 
			
		||||
    <div class="form-group row">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.address1') }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" name="address1" :placeholder="trans('texts.address1')" v-model="data.address1" class="form-control" id="address1">
 | 
			
		||||
                <div v-if="errors && errors.address1" class="text-danger">{{ errors.address1[0] }}</div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="form-group row">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.address2') }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" name="address2" :placeholder="trans('texts.address2')" v-model="data.address2" class="form-control" id="address2">
 | 
			
		||||
            <div v-if="errors && errors.address2" class="text-danger">{{ errors.address2[0] }}</div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="form-group row">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.city') }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" name="city" :placeholder="trans('texts.city')" v-model="data.city" class="form-control" id="city">
 | 
			
		||||
            <div v-if="errors && errors.city" class="text-danger">{{ errors.city[0] }}</div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="form-group row">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.state') }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" name="state" :placeholder="trans('texts.state')" v-model="data.state" class="form-control" id="state">
 | 
			
		||||
            <div v-if="errors && errors.state" class="text-danger">{{ errors.state[0] }}</div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="form-group row">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.postal_code') }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" name="postal_code" :placeholder="trans('texts.postal_code')" v-model="data.postal_code" class="form-control" id="postal_code">
 | 
			
		||||
            <div v-if="errors && errors.postal_code" class="text-danger">{{ errors.postal_code[0] }}</div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="form-group row">
 | 
			
		||||
        <label for="name" class="col-sm-3 col-form-label text-right">{{ trans('texts.country') }}</label>
 | 
			
		||||
        <div class="col-sm-9">
 | 
			
		||||
            <input type="text" name="country" :placeholder="trans('texts.country')" v-model="data.country" class="form-control" id="country">
 | 
			
		||||
            <div v-if="errors && errors.country" class="text-danger">{{ errors.country[0] }}</div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>	
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
	export default {
 | 
			
		||||
        props: ['data', 'errors'],
 | 
			
		||||
        default: () => {}
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
@ -1,117 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
 | 
			
		||||
	<div class="d-flex justify-content-start">
 | 
			
		||||
 | 
			
		||||
    <div class="p-2">
 | 
			
		||||
      
 | 
			
		||||
      <div class="btn-group">
 | 
			
		||||
        <button class="btn btn-primary btn-lg dropdown-toggle" type="button" :disabled="getBulkCount() == 0" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ trans('texts.action') }} <span v-if="getBulkCount() > 0">({{ getBulkCount() }})</span></button>
 | 
			
		||||
          <div class="dropdown-menu" x-placement="bottom-start" style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(0px, 44px, 0px);">
 | 
			
		||||
            <a class="dropdown-item" @click="archive" href="#">{{ trans('texts.archive') }}</a>
 | 
			
		||||
            <a class="dropdown-item" @click="restore" href="#">{{ trans('texts.restore') }}</a>
 | 
			
		||||
            <a class="dropdown-item" @click="del" href="#">{{ trans('texts.delete') }}</a>
 | 
			
		||||
          </div>
 | 
			
		||||
      </div>
 | 
			
		||||
            
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="p-2">
 | 
			
		||||
      <vuetable-multi-select :select_options="listaction.multi_select"></vuetable-multi-select>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="mr-auto p-2">
 | 
			
		||||
      <div class="input-group mb-3">
 | 
			
		||||
 | 
			
		||||
        <select class="custom-select" id="per_page" v-model="per_page" @change="updatePerPage()">
 | 
			
		||||
          <option value="10">10</option>
 | 
			
		||||
          <option value="25">25</option>
 | 
			
		||||
          <option value="50">50</option>
 | 
			
		||||
          <option value="100">100</option>
 | 
			
		||||
        </select>
 | 
			
		||||
        
 | 
			
		||||
        <div class="input-group-append">
 | 
			
		||||
          <label class="input-group-text" for="per_page">{{trans('texts.rows')}}</label>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="ml-auto p-2">
 | 
			
		||||
    	<vuetable-query-filter></vuetable-query-filter>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="p-2">
 | 
			
		||||
      <button class="btn btn-primary btn-lg " @click="goToUrl(listaction.create_entity.url)" :disabled="isDisabled">{{ trans('texts.new_client') }}</button>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    props: {
 | 
			
		||||
      listaction: {
 | 
			
		||||
        type: Object,
 | 
			
		||||
        required: true
 | 
			
		||||
      },
 | 
			
		||||
      per_page_prop: {
 | 
			
		||||
        type: Number,
 | 
			
		||||
        required: true
 | 
			
		||||
      }
 | 
			
		||||
    },  
 | 
			
		||||
    data () {
 | 
			
		||||
      return {
 | 
			
		||||
 | 
			
		||||
        per_page: this.per_page_prop
 | 
			
		||||
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      archive () {
 | 
			
		||||
 | 
			
		||||
        this.$events.fire('bulk-action', 'archive') 
 | 
			
		||||
 | 
			
		||||
      },
 | 
			
		||||
      del () {
 | 
			
		||||
 | 
			
		||||
        this.$events.fire('bulk-action', 'delete')
 | 
			
		||||
 | 
			
		||||
      },
 | 
			
		||||
      restore() {
 | 
			
		||||
 | 
			
		||||
        this.$events.fire('bulk-action', 'restore')
 | 
			
		||||
 | 
			
		||||
      },
 | 
			
		||||
      getBulkCount() {
 | 
			
		||||
 | 
			
		||||
        return this.$store.getters['client_list/getBulkCount']
 | 
			
		||||
 | 
			
		||||
      },
 | 
			
		||||
      goToUrl: function (url) {
 | 
			
		||||
 | 
			
		||||
        location.href=url
 | 
			
		||||
 | 
			
		||||
      },
 | 
			
		||||
      updatePerPage() {
 | 
			
		||||
 | 
			
		||||
        this.$events.fire('perpage_action', this.per_page)
 | 
			
		||||
      
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
   computed: {
 | 
			
		||||
      isDisabled() :any
 | 
			
		||||
      {
 | 
			
		||||
        return !this.listaction.create_entity.create_permission;
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
select.custom-select {
 | 
			
		||||
    height: 42px;
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
@ -1,23 +0,0 @@
 | 
			
		||||
export default {
 | 
			
		||||
  table: {
 | 
			
		||||
    tableClass: 'table table-striped table-hover',
 | 
			
		||||
    loadingClass: 'loading',
 | 
			
		||||
    ascendingIcon: 'fa fa-angle-double-up',
 | 
			
		||||
    descendingIcon: 'fa fa-angle-double-down',
 | 
			
		||||
    handleIcon: 'glyphicon glyphicon-menu-hamburger',
 | 
			
		||||
  },
 | 
			
		||||
  pagination: {
 | 
			
		||||
    infoClass: 'pull-left',
 | 
			
		||||
    wrapperClass: 'vuetable-pagination pull-right',
 | 
			
		||||
    activeClass: 'btn-primary',
 | 
			
		||||
    disabledClass: 'disabled',
 | 
			
		||||
    pageClass: 'btn btn-border',
 | 
			
		||||
    linkClass: 'btn btn-border',
 | 
			
		||||
    icons: {
 | 
			
		||||
      first: '',
 | 
			
		||||
      prev: '',
 | 
			
		||||
      next: '',
 | 
			
		||||
      last: '',
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,51 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
  
 | 
			
		||||
        <div class="input-group">
 | 
			
		||||
 | 
			
		||||
          <input type="text" v-model="filterText" class="form-control" @keyup.enter="doFilter" placeholder="search">
 | 
			
		||||
          <button class="btn btn-primary" style="margin-left:15px;" @click="doFilter">Go</button>
 | 
			
		||||
          <!--<button class="btn btn-light" @click="resetFilter">Reset</button>-->
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
      
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  
 | 
			
		||||
  import Vue from 'vue'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    data () {
 | 
			
		||||
      return {
 | 
			
		||||
 | 
			
		||||
        filterText: ''
 | 
			
		||||
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      doFilter () {
 | 
			
		||||
 | 
			
		||||
        this.$store.commit('client_list/setFilterText', this.filterText)
 | 
			
		||||
        this.$events.fire('filter-set','')
 | 
			
		||||
 | 
			
		||||
      },
 | 
			
		||||
      resetFilter () {
 | 
			
		||||
 | 
			
		||||
        this.$store.commit('client_list/setFilterText', '')
 | 
			
		||||
        this.$events.fire('filter-set','')
 | 
			
		||||
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
 | 
			
		||||
  .form-inline > * {
 | 
			
		||||
     margin:5px 10px;
 | 
			
		||||
  }
 | 
			
		||||
  .form-control {
 | 
			
		||||
    min-height: 40px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@ -1,54 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div style="width:300px;">
 | 
			
		||||
    <multiselect v-model="value" 
 | 
			
		||||
    :options="options" 
 | 
			
		||||
    :multiple="true"
 | 
			
		||||
    :placeholder="trans('texts.status')"
 | 
			
		||||
    :preselect-first="true"
 | 
			
		||||
    label="name"
 | 
			
		||||
    track-by="name"
 | 
			
		||||
    @input="onChange"
 | 
			
		||||
    ></multiselect>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
 | 
			
		||||
  import Multiselect from 'vue-multiselect'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    components: { Multiselect },
 | 
			
		||||
    props:['select_options'],
 | 
			
		||||
    data () {
 | 
			
		||||
      return {
 | 
			
		||||
        value : [],
 | 
			
		||||
        options: this.select_options
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
 | 
			
		||||
      this.$events.fire('multi-select', '')
 | 
			
		||||
    
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      onChange (value) {
 | 
			
		||||
 | 
			
		||||
        this.$store.commit('client_list/setStatusArray', value)
 | 
			
		||||
        this.$events.fire('multi-select', '')
 | 
			
		||||
 | 
			
		||||
        if (value.indexOf('Reset me!') !== -1) this.value = []
 | 
			
		||||
 | 
			
		||||
      },
 | 
			
		||||
      onSelect (option) {
 | 
			
		||||
 | 
			
		||||
        if (option === 'Disable me!') this.isDisabled = true
 | 
			
		||||
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
</style>
 | 
			
		||||
@ -1,37 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <ul class="pagination">
 | 
			
		||||
    <li :class="{'disabled': isOnFirstPage}">
 | 
			
		||||
      <a href="" @click.prevent="loadPage('prev')">
 | 
			
		||||
        <span>«</span>
 | 
			
		||||
      </a>
 | 
			
		||||
    </li>
 | 
			
		||||
    
 | 
			
		||||
    <template v-if="notEnoughPages">
 | 
			
		||||
      <li v-for="n in totalPage" :class="{'active': isCurrentPage(n)}">
 | 
			
		||||
        <a @click.prevent="loadPage(n)" v-html="n"></a>
 | 
			
		||||
      </li>
 | 
			
		||||
    </template>
 | 
			
		||||
 | 
			
		||||
    <template v-else>
 | 
			
		||||
      <li v-for="n in windowSize" :class="{'active': isCurrentPage(windowStart+n-1)}">
 | 
			
		||||
        <a @click.prevent="loadPage(windowStart+n-1)" v-html="windowStart+n-1"></a>
 | 
			
		||||
      </li>
 | 
			
		||||
    </template>
 | 
			
		||||
 | 
			
		||||
    <li :class="{'disabled': isOnLastPage}">
 | 
			
		||||
      <a href="" @click.prevent="loadPage('next')">
 | 
			
		||||
        <span>»</span>
 | 
			
		||||
      </a>
 | 
			
		||||
    </li>
 | 
			
		||||
  </ul>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
import VuetablePaginationMixin from 'vuetable-2/src/components/VuetablePaginationMixin'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  mixins: [VuetablePaginationMixin]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
@ -1,37 +0,0 @@
 | 
			
		||||
export default class ClientContact {
 | 
			
		||||
 | 
			
		||||
	id: number
 | 
			
		||||
	client_id: number
 | 
			
		||||
	user_id: number
 | 
			
		||||
	company_id: number
 | 
			
		||||
	first_name: string 
 | 
			
		||||
	last_name: string 
 | 
			
		||||
	phone: string 
 | 
			
		||||
	custom_value1: string 
 | 
			
		||||
	custom_value2: string 
 | 
			
		||||
	email: string 
 | 
			
		||||
	email_verified_at: string 
 | 
			
		||||
	confirmation_code: string 
 | 
			
		||||
	is_primary: boolean 
 | 
			
		||||
	confirmed: boolean 
 | 
			
		||||
	failed_logins: number 
 | 
			
		||||
	oauth_user_id: string 
 | 
			
		||||
	oauth_provider_id: string 
 | 
			
		||||
	google_2fa_secret: string 
 | 
			
		||||
	accepted_terms_version: string 
 | 
			
		||||
	avatar: string 
 | 
			
		||||
	avatar_width: string 
 | 
			
		||||
	avatar_height: string 
 | 
			
		||||
	avatar_size: string 
 | 
			
		||||
	db: string 
 | 
			
		||||
	password: string 
 | 
			
		||||
	remember_token: string
 | 
			
		||||
	deleted_at: string 
 | 
			
		||||
	created_at: string 
 | 
			
		||||
	updated_at: string
 | 
			
		||||
 | 
			
		||||
	public constructor(init?:Partial<ClientContact>) {
 | 
			
		||||
	        (<any>Object).assign(this, init);
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,43 +0,0 @@
 | 
			
		||||
export default class Client {
 | 
			
		||||
 | 
			
		||||
	id: number
 | 
			
		||||
	name: string
 | 
			
		||||
	user_id: number
 | 
			
		||||
	company_id: number
 | 
			
		||||
	website: string 
 | 
			
		||||
	private_notes: string 
 | 
			
		||||
	balance: number 
 | 
			
		||||
	paid_to_date: number 
 | 
			
		||||
	last_login: string 
 | 
			
		||||
	industry_id: number 
 | 
			
		||||
	size_id: number 
 | 
			
		||||
	currency_id: number 
 | 
			
		||||
	address1: string 
 | 
			
		||||
	address2: string 
 | 
			
		||||
	city: string 
 | 
			
		||||
	state: string 
 | 
			
		||||
	postal_code: string 
 | 
			
		||||
	country_id: number 
 | 
			
		||||
	latitude: number
 | 
			
		||||
	longitude: number
 | 
			
		||||
	shipping_latitude: number
 | 
			
		||||
	shipping_longitude: number
 | 
			
		||||
	custom_value1: string 
 | 
			
		||||
	custom_value2: string 
 | 
			
		||||
	shipping_address1: string 
 | 
			
		||||
	shipping_address2: string 
 | 
			
		||||
	shipping_city: string 
 | 
			
		||||
	shipping_state: string 
 | 
			
		||||
	shipping_postal_code: string 
 | 
			
		||||
	shipping_country_id: number 
 | 
			
		||||
	is_deleted: boolean 
 | 
			
		||||
	payment_terms: string 
 | 
			
		||||
	vat_number: string 
 | 
			
		||||
	id_number: string 
 | 
			
		||||
	created_at: string 
 | 
			
		||||
	updated_at: string
 | 
			
		||||
 | 
			
		||||
	public constructor(init?:Partial<Client>) {
 | 
			
		||||
	        (<any>Object).assign(this, init);
 | 
			
		||||
	    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,21 +0,0 @@
 | 
			
		||||
export default class ClientSettings {
 | 
			
		||||
 | 
			
		||||
	timezone_id:number
 | 
			
		||||
	language_id:number
 | 
			
		||||
	currency_id:number
 | 
			
		||||
	default_task_rate:number
 | 
			
		||||
	send_reminders:boolean
 | 
			
		||||
	show_tasks_in_portal:boolean
 | 
			
		||||
	custom_message_dashboard:string
 | 
			
		||||
	custom_message_unpaid_invoice:string
 | 
			
		||||
	custom_message_paid_invoice:string
 | 
			
		||||
	custom_message_unapproved_quote:string
 | 
			
		||||
	show_currency_symbol:boolean
 | 
			
		||||
	show_currency_code:boolean
 | 
			
		||||
	industry_id:number
 | 
			
		||||
	size_id:number
 | 
			
		||||
 | 
			
		||||
	constructor(init?:Partial<ClientSettings>) {
 | 
			
		||||
	        (<any>Object).assign(this, init);
 | 
			
		||||
	    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,13 +0,0 @@
 | 
			
		||||
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import VueSelect from 'vue-select';
 | 
			
		||||
 | 
			
		||||
Vue.component('v-select', VueSelect.VueSelect)
 | 
			
		||||
 | 
			
		||||
new Vue({
 | 
			
		||||
  el: '#localization',
 | 
			
		||||
  data: {
 | 
			
		||||
    options: ['jim','bob','frank'],
 | 
			
		||||
    selected: 'frank',
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										4
									
								
								resources/js/src/shims-vue.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								resources/js/src/shims-vue.d.ts
									
									
									
									
										vendored
									
									
								
							@ -1,4 +0,0 @@
 | 
			
		||||
declare module '*.vue' {
 | 
			
		||||
  import Vue from 'vue'
 | 
			
		||||
  export default Vue
 | 
			
		||||
}
 | 
			
		||||
@ -1,16 +0,0 @@
 | 
			
		||||
import Vue from 'vue'
 | 
			
		||||
import Vuex from 'vuex'
 | 
			
		||||
import client_list from './modules/client_list'
 | 
			
		||||
 | 
			
		||||
Vue.use(Vuex)
 | 
			
		||||
 | 
			
		||||
const debug = process.env.NODE_ENV !== 'production'
 | 
			
		||||
 | 
			
		||||
const store =  new Vuex.Store({
 | 
			
		||||
  modules: {
 | 
			
		||||
    client_list
 | 
			
		||||
  },
 | 
			
		||||
  strict: debug,
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export default store
 | 
			
		||||
@ -1,70 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * State managment for the Client List View
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
const state = {
 | 
			
		||||
  statuses: [{value: 'active'}],
 | 
			
		||||
  filter_text: '',
 | 
			
		||||
  bulk_count : 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getters
 | 
			
		||||
const getters = {
 | 
			
		||||
  getBulkCount: state => {
 | 
			
		||||
 | 
			
		||||
    return state.bulk_count
 | 
			
		||||
  
 | 
			
		||||
  }, 
 | 
			
		||||
	getFilterText: state => {
 | 
			
		||||
 | 
			
		||||
		return state.filter_text
 | 
			
		||||
 | 
			
		||||
	},
 | 
			
		||||
  getQueryStringObject: state => {
 | 
			
		||||
 | 
			
		||||
    var values = state.statuses.map(function (state, index, array) {
 | 
			
		||||
         return state.value; 
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    var queryObj = {
 | 
			
		||||
      filter: state.filter_text,
 | 
			
		||||
      status: [].concat.apply([], values).join(",")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return queryObj
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// actions
 | 
			
		||||
const actions = {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// mutations
 | 
			
		||||
const mutations = {
 | 
			
		||||
	setFilterText(state, text) {
 | 
			
		||||
 | 
			
		||||
    state.filter_text = text
 | 
			
		||||
 | 
			
		||||
	},
 | 
			
		||||
  setStatusArray(state, statuses) {
 | 
			
		||||
 | 
			
		||||
    state.statuses = statuses
 | 
			
		||||
 | 
			
		||||
  },
 | 
			
		||||
  setBulkCount(state, count) {
 | 
			
		||||
 | 
			
		||||
    state.bulk_count = count
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
 | 
			
		||||
  namespaced: true,
 | 
			
		||||
  state,
 | 
			
		||||
  getters,
 | 
			
		||||
  actions,
 | 
			
		||||
  mutations
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
@ -1,3 +0,0 @@
 | 
			
		||||
export function sum(x: number, y: number): number {
 | 
			
		||||
  return x + y;
 | 
			
		||||
}
 | 
			
		||||
@ -1,13 +0,0 @@
 | 
			
		||||
import { sum } from "./math";
 | 
			
		||||
 | 
			
		||||
describe("This is a simple test", () => {
 | 
			
		||||
    test("Check the sum of 0 + 0", () => {
 | 
			
		||||
			expect(sum(0,0)).toBe(0);
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describe("This is a simple test", () => {
 | 
			
		||||
    test("Check the sum of 1 + 2", () => {
 | 
			
		||||
		expect(sum(1, 2)).toBe(3);    
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
@ -1,129 +0,0 @@
 | 
			
		||||
import CSettings from '../models/client-settings-model';
 | 
			
		||||
 | 
			
		||||
export default class ClientSettings {
 | 
			
		||||
 | 
			
		||||
	client_settings:any
 | 
			
		||||
 | 
			
		||||
	company_settings:any
 | 
			
		||||
 | 
			
		||||
	settings:any
 | 
			
		||||
 | 
			
		||||
	languages:any
 | 
			
		||||
 | 
			
		||||
    currencies:any
 | 
			
		||||
 | 
			
		||||
    payment_terms:any
 | 
			
		||||
 | 
			
		||||
    industries:any
 | 
			
		||||
 | 
			
		||||
    sizes:any
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new Client Settings instance.
 | 
			
		||||
     */
 | 
			
		||||
    constructor(
 | 
			
		||||
        client_settings: any, 
 | 
			
		||||
        company_settings: any, 
 | 
			
		||||
        languages: any,
 | 
			
		||||
        currencies: any,
 | 
			
		||||
        payment_terms: any,
 | 
			
		||||
        industries: any,
 | 
			
		||||
        sizes: any
 | 
			
		||||
        ) {
 | 
			
		||||
    	this.client_settings = client_settings
 | 
			
		||||
    	this.company_settings = company_settings
 | 
			
		||||
    	this.languages = languages
 | 
			
		||||
        this.currencies = currencies
 | 
			
		||||
        this.payment_terms = payment_terms
 | 
			
		||||
        this.industries = industries
 | 
			
		||||
        this.sizes = sizes
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Build Settings object
 | 
			
		||||
     */
 | 
			
		||||
    build() {
 | 
			
		||||
 | 
			
		||||
        this.settings = new CSettings(this.client_settings)
 | 
			
		||||
        if (this.client_settings.currency_id !== null) { 
 | 
			
		||||
 | 
			
		||||
            this.settings.currency_id = this.currencies.find(obj => {
 | 
			
		||||
                                            return obj.id == this.client_settings.currency_id
 | 
			
		||||
                                        })
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(this.client_settings.show_currency_symbol == null)
 | 
			
		||||
            this.settings.show_currency_symbol = this.company_settings.show_currency_symbol
 | 
			
		||||
 | 
			
		||||
        if(this.client_settings.show_currency_code == null)
 | 
			
		||||
            this.settings.show_currency_code = this.company_settings.show_currency_code
 | 
			
		||||
 | 
			
		||||
        if (this.client_settings.language_id !== null) { 
 | 
			
		||||
 | 
			
		||||
            this.settings.language_id = this.languages.find(obj => {
 | 
			
		||||
                                            return obj.id == this.client_settings.language_id
 | 
			
		||||
                                        })
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.client_settings.payment_terms !== null) { 
 | 
			
		||||
 | 
			
		||||
            this.settings.payment_terms = this.payment_terms.find(obj => {
 | 
			
		||||
                                            return obj.id == this.client_settings.payment_terms
 | 
			
		||||
                                        })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.settings.default_task_rate = this.client_settings.default_task_rate ? this.client_settings.default_task_rate : this.company_settings.default_task_rate
 | 
			
		||||
 | 
			
		||||
        if(this.client_settings.send_reminders)
 | 
			
		||||
            this.settings.send_reminders = this.client_settings.send_reminders
 | 
			
		||||
        else
 | 
			
		||||
            this.settings.send_reminders = this.company_settings.send_reminders
 | 
			
		||||
 | 
			
		||||
        if(this.client_settings.show_tasks_in_portal)
 | 
			
		||||
            this.settings.show_tasks_in_portal = this.client_settings.show_tasks_in_portal
 | 
			
		||||
        else
 | 
			
		||||
            this.settings.show_tasks_in_portal = this.company_settings.show_tasks_in_portal
 | 
			
		||||
 | 
			
		||||
        if(this.client_settings.custom_message_dashboard && this.client_settings.custom_message_dashboard.length >=1)
 | 
			
		||||
            this.settings.custom_message_dashboard = this.client_settings.custom_message_dashboard
 | 
			
		||||
        else
 | 
			
		||||
            this.settings.custom_message_dashboard = this.company_settings.custom_message_dashboard
 | 
			
		||||
 | 
			
		||||
        if(this.client_settings.custom_message_unpaid_invoice && this.client_settings.custom_message_unpaid_invoice.length >=1)
 | 
			
		||||
            this.settings.custom_message_unpaid_invoice = this.client_settings.custom_message_unpaid_invoice
 | 
			
		||||
        else
 | 
			
		||||
            this.settings.custom_message_unpaid_invoice = this.company_settings.custom_message_unpaid_invoice
 | 
			
		||||
 | 
			
		||||
        if(this.client_settings.custom_message_paid_invoice && this.client_settings.custom_message_paid_invoice.length >=1)
 | 
			
		||||
            this.settings.custom_message_paid_invoice = this.client_settings.custom_message_paid_invoice
 | 
			
		||||
        else
 | 
			
		||||
            this.settings.custom_message_paid_invoice = this.company_settings.custom_message_paid_invoice
 | 
			
		||||
 | 
			
		||||
        if(this.client_settings.custom_message_unapproved_quote && this.client_settings.custom_message_unapproved_quote.length >=1)
 | 
			
		||||
            this.settings.custom_message_unapproved_quote = this.client_settings.custom_message_unapproved_quote
 | 
			
		||||
        else
 | 
			
		||||
            this.settings.custom_message_unapproved_quote = this.company_settings.custom_message_unapproved_quote
 | 
			
		||||
 | 
			
		||||
        if (this.client_settings.industry_id !== null) { 
 | 
			
		||||
 | 
			
		||||
            this.settings.industry_id = this.industries.find(obj => {
 | 
			
		||||
                                            return obj.id == this.client_settings.industry_id
 | 
			
		||||
                                        })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.client_settings.size_id !== null) { 
 | 
			
		||||
 | 
			
		||||
            this.settings.size_id = this.sizes.find(obj => {
 | 
			
		||||
                                            return obj.id == this.client_settings.size_id
 | 
			
		||||
                                        })
 | 
			
		||||
        }         
 | 
			
		||||
 | 
			
		||||
        return this.settings
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,74 +0,0 @@
 | 
			
		||||
export default class FormErrors {
 | 
			
		||||
 | 
			
		||||
	errors:any;
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new Errors instance.
 | 
			
		||||
     */
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.errors = {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determine if an errors exists for the given field.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} field
 | 
			
		||||
     */
 | 
			
		||||
    has(field:string) {
 | 
			
		||||
        return this.errors.hasOwnProperty(field);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determine if we have any errors.
 | 
			
		||||
     */
 | 
			
		||||
    any() {
 | 
			
		||||
        return Object.keys(this.errors).length > 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieve the error message for a field.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} field
 | 
			
		||||
     */
 | 
			
		||||
    get(field:string) {
 | 
			
		||||
        if (this.errors[field]) {
 | 
			
		||||
            return this.errors[field][0];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Record the new errors.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {object} errors
 | 
			
		||||
     */
 | 
			
		||||
    record(errors:any) {
 | 
			
		||||
        this.errors = errors;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clear one or all error fields.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string|null} field
 | 
			
		||||
     */
 | 
			
		||||
    clear(field:string) {
 | 
			
		||||
        if (field) {
 | 
			
		||||
            delete this.errors[field];
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.errors = {};
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//@keydown="errors.clear($event.target.name)"
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
@ -1,175 +0,0 @@
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
import FormErrors from '../utils/form-errors';
 | 
			
		||||
 | 
			
		||||
export default class Form {
 | 
			
		||||
 | 
			
		||||
    errors:any;
 | 
			
		||||
 | 
			
		||||
    originalData:any;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new Form instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {object} data
 | 
			
		||||
     */
 | 
			
		||||
    constructor(data) {
 | 
			
		||||
 | 
			
		||||
        this.originalData = data;
 | 
			
		||||
 | 
			
		||||
        for (let field in data) {
 | 
			
		||||
            this[field] = data[field];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.errors = new FormErrors();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch all relevant data for the form.
 | 
			
		||||
     */
 | 
			
		||||
    data() {
 | 
			
		||||
 | 
			
		||||
        let data = {};
 | 
			
		||||
 | 
			
		||||
        for (let property in this.originalData) {
 | 
			
		||||
            data[property] = this[property];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return data;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reset the form fields.
 | 
			
		||||
     */
 | 
			
		||||
    reset() {
 | 
			
		||||
 | 
			
		||||
        for (let field in this.originalData) {
 | 
			
		||||
            this[field] = '';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.errors.clear();
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Send a POST request to the given URL.
 | 
			
		||||
     * .
 | 
			
		||||
     * @param {string} url
 | 
			
		||||
     */
 | 
			
		||||
    post(url) {
 | 
			
		||||
 | 
			
		||||
        return this.submit('post', url);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Send a PUT request to the given URL.
 | 
			
		||||
     * .
 | 
			
		||||
     * @param {string} url
 | 
			
		||||
     */
 | 
			
		||||
    put(url:string) {
 | 
			
		||||
 | 
			
		||||
        return this.submit('put', url);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Send a PATCH request to the given URL.
 | 
			
		||||
     * .
 | 
			
		||||
     * @param {string} url
 | 
			
		||||
     */
 | 
			
		||||
    patch(url:string) {
 | 
			
		||||
 | 
			
		||||
        return this.submit('patch', url);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Send a DELETE request to the given URL.
 | 
			
		||||
     * .
 | 
			
		||||
     * @param {string} url
 | 
			
		||||
     */
 | 
			
		||||
    delete(url:string) {
 | 
			
		||||
 | 
			
		||||
        return this.submit('delete', url);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Submit the form.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} requestType
 | 
			
		||||
     * @param {string} url
 | 
			
		||||
     */
 | 
			
		||||
    submit(requestType:string, url:string) {
 | 
			
		||||
 | 
			
		||||
        return new Promise((resolve, reject) => {
 | 
			
		||||
 | 
			
		||||
            axios[requestType](url, this.data())
 | 
			
		||||
                .then(response => {
 | 
			
		||||
 | 
			
		||||
                    this.onSuccess(response.data);
 | 
			
		||||
 | 
			
		||||
                    resolve(response.data);
 | 
			
		||||
 | 
			
		||||
                })
 | 
			
		||||
                .catch(error => {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                    if (error.response.status === 422) {
 | 
			
		||||
 | 
			
		||||
                        this.onFail(error.response.data.errors);
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
                    else if(error.response.status === 419) {
 | 
			
		||||
 | 
			
		||||
                        //csrf token has expired, we'll need to force a page reload
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    reject(error.response.data);
 | 
			
		||||
 | 
			
		||||
                                      
 | 
			
		||||
                });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
    * Update form data on success
 | 
			
		||||
    *
 | 
			
		||||
    * @param {object} data
 | 
			
		||||
    */
 | 
			
		||||
    update(data)
 | 
			
		||||
    {
 | 
			
		||||
        this.originalData = data;
 | 
			
		||||
 | 
			
		||||
        for (let field in data) {
 | 
			
		||||
            this[field] = data[field];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handle a successful form submission.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {object} data
 | 
			
		||||
     */
 | 
			
		||||
    onSuccess(data) {
 | 
			
		||||
        this.update(data);
 | 
			
		||||
        this.errors.clear();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handle a failed form submission.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {object} errors
 | 
			
		||||
     */
 | 
			
		||||
    onFail(errors) {
 | 
			
		||||
 | 
			
		||||
        this.errors.record(errors);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@ -1,34 +0,0 @@
 | 
			
		||||
export default class NumberFormat {
 | 
			
		||||
 | 
			
		||||
	amount:any
 | 
			
		||||
 | 
			
		||||
	currency:any
 | 
			
		||||
 | 
			
		||||
	symbol_decorator:boolean
 | 
			
		||||
 | 
			
		||||
	language:any
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new Number Format instance.
 | 
			
		||||
     */
 | 
			
		||||
    constructor(amount: any, currency: any, symbol_decorator: boolean, language: any) {
 | 
			
		||||
    	this.amount = amount
 | 
			
		||||
    	this.currency = currency
 | 
			
		||||
    	this.symbol_decorator = symbol_decorator
 | 
			
		||||
    	this.language = language
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    format() {
 | 
			
		||||
    	this.amount = new Intl.NumberFormat(this.language.locale.replace("_", "-"), {style: 'decimal',currency: this.currency.code} ).format(this.amount)
 | 
			
		||||
 | 
			
		||||
    	if(this.symbol_decorator)
 | 
			
		||||
    		this.amount = this.currency.symbol + this.amount
 | 
			
		||||
    	else
 | 
			
		||||
    		this.amount = this.amount + " " + this.currency.code
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    	return this.amount
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -95,24 +95,26 @@ class MigrationTest extends TestCase
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testMigrationFileUpload()
 | 
			
		||||
    {
 | 
			
		||||
        $file = new UploadedFile(base_path('tests/Unit/Migration/migration.zip'), 'migration.zip');
 | 
			
		||||
    // public function testMigrationFileUpload()
 | 
			
		||||
    // {
 | 
			
		||||
    //     $file = new UploadedFile(base_path('tests/Unit/Migration/migration.zip'), 'migration.zip');
 | 
			
		||||
 | 
			
		||||
        $data = [
 | 
			
		||||
            'migration' => $file,
 | 
			
		||||
            'force' => true,
 | 
			
		||||
        ];
 | 
			
		||||
    //     $data = [
 | 
			
		||||
    //         'migration' => $file,
 | 
			
		||||
    //         'force' => true,
 | 
			
		||||
    //     ];
 | 
			
		||||
 | 
			
		||||
        $token = $this->company->tokens->first()->token;
 | 
			
		||||
    //     $token = $this->company->tokens->first()->token;
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
                'X-API-TOKEN' => $token,
 | 
			
		||||
                'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
                'X-Requested-With' => 'XMLHttpRequest',
 | 
			
		||||
                'X-API-PASSWORD' => 'ALongAndBriliantPassword',
 | 
			
		||||
            ])->post('/api/v1/migration/start', $data);
 | 
			
		||||
    //     $response = $this->withHeaders([
 | 
			
		||||
    //             'X-API-TOKEN' => $token,
 | 
			
		||||
    //             'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
    //             'X-Requested-With' => 'XMLHttpRequest',
 | 
			
		||||
    //             'X-API-PASSWORD' => 'ALongAndBriliantPassword',
 | 
			
		||||
    //         ])->post('/api/v1/migration/start', $data);
 | 
			
		||||
 | 
			
		||||
    //     $response->assertStatus(200);
 | 
			
		||||
    //     $this->assertTrue(file_exists(base_path('storage/migrations/migration/migration.json')));
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -35,10 +35,17 @@ class DesignTest extends TestCase
 | 
			
		||||
 | 
			
		||||
    	$this->assertNotNull($html);
 | 
			
		||||
 | 
			
		||||
    	//\Log::error($html);
 | 
			
		||||
 | 
			
		||||
        $this->invoice = factory(\App\Models\Invoice::class)->create([
 | 
			
		||||
                'user_id' => $this->user->id,
 | 
			
		||||
                'client_id' => $this->client->id,
 | 
			
		||||
                'company_id' => $this->company->id,
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
        $this->invoice->uses_inclusive_taxes = false;
 | 
			
		||||
 | 
			
		||||
    	$settings = $this->invoice->client->settings;
 | 
			
		||||
    	$settings->invoice_design_id = "5";
 | 
			
		||||
    	$settings->invoice_design_id = "6";
 | 
			
		||||
 | 
			
		||||
    	$this->client->settings = $settings;
 | 
			
		||||
    	$this->client->save();
 | 
			
		||||
@ -60,7 +67,7 @@ class DesignTest extends TestCase
 | 
			
		||||
    	//\Log::error($html);
 | 
			
		||||
 | 
			
		||||
    	$settings = $this->invoice->client->settings;
 | 
			
		||||
    	$settings->quote_design_id = "10";
 | 
			
		||||
    	$settings->quote_design_id = "6";
 | 
			
		||||
 | 
			
		||||
    	$this->client->settings = $settings;
 | 
			
		||||
    	$this->client->save();
 | 
			
		||||
 | 
			
		||||
@ -91,8 +91,6 @@ trait MockAccountData
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $this->account = factory(\App\Models\Account::class)->create();
 | 
			
		||||
        $this->company = factory(\App\Models\Company::class)->create([
 | 
			
		||||
            'account_id' => $this->account->id,
 | 
			
		||||
@ -189,9 +187,16 @@ trait MockAccountData
 | 
			
		||||
        $this->client->group_settings_id = $gs->id;
 | 
			
		||||
        $this->client->save();
 | 
			
		||||
 
 | 
			
		||||
        $this->invoice = InvoiceFactory::create($this->company->id,$this->user->id);//stub the company and user_id
 | 
			
		||||
        $this->invoice = InvoiceFactory::create($this->company->id, $this->user->id);//stub the company and user_id
 | 
			
		||||
        $this->invoice->client_id = $this->client->id;
 | 
			
		||||
 | 
			
		||||
        // $this->invoice = factory(\App\Models\Invoice::class)->create([
 | 
			
		||||
        //         'user_id' => $this->user->id,
 | 
			
		||||
        //         'client_id' => $this->client->id,
 | 
			
		||||
        //         'company_id' => $this->company->id,
 | 
			
		||||
        //     ]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		$this->invoice->line_items = $this->buildLineItems();
 | 
			
		||||
		$this->invoice->uses_inclusive_taxes = false;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -103,13 +103,10 @@ class ImportTest extends TestCase
 | 
			
		||||
        $this->makeTestData();
 | 
			
		||||
 | 
			
		||||
        $this->invoice->forceDelete();
 | 
			
		||||
        $this->quote->forceDelete();
 | 
			
		||||
 | 
			
		||||
        $original_count = Invoice::count();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        //$this->migration_array = json_decode(file_get_contents($migration_file), 1);
 | 
			
		||||
 | 
			
		||||
        Import::dispatchNow($this->migration_array, $this->company, $this->user);
 | 
			
		||||
 | 
			
		||||
        $this->assertGreaterThan($original_count, Invoice::count());
 | 
			
		||||
@ -149,7 +146,7 @@ class ImportTest extends TestCase
 | 
			
		||||
        //$this->makeTestData();
 | 
			
		||||
 | 
			
		||||
        $this->invoice->forceDelete();
 | 
			
		||||
 | 
			
		||||
        $this->quote->forceDelete();
 | 
			
		||||
        // $migration_file = base_path() . '/tests/Unit/Migration/migration.json';
 | 
			
		||||
 | 
			
		||||
        // $this->migration_array = json_decode(file_get_contents($migration_file), 1);
 | 
			
		||||
@ -190,7 +187,7 @@ class ImportTest extends TestCase
 | 
			
		||||
        $original_number = Invoice::count();
 | 
			
		||||
 | 
			
		||||
        $this->invoice->forceDelete();
 | 
			
		||||
 | 
			
		||||
        $this->quote->forceDelete();
 | 
			
		||||
        // $migration_file = base_path() . '/tests/Unit/Migration/migration.json';
 | 
			
		||||
 | 
			
		||||
        // $this->migration_array = json_decode(file_get_contents($migration_file), 1);
 | 
			
		||||
@ -264,7 +261,7 @@ class ImportTest extends TestCase
 | 
			
		||||
        $original_count = Payment::count();
 | 
			
		||||
 | 
			
		||||
        $this->invoice->forceDelete();
 | 
			
		||||
 | 
			
		||||
        $this->quote->forceDelete();
 | 
			
		||||
        // $migration_file = base_path() . '/tests/Unit/Migration/migration.json';
 | 
			
		||||
 | 
			
		||||
        // $this->migration_array = json_decode(file_get_contents($migration_file), 1);
 | 
			
		||||
@ -295,6 +292,7 @@ class ImportTest extends TestCase
 | 
			
		||||
        $original_count = Credit::count();
 | 
			
		||||
 | 
			
		||||
        $this->invoice->forceDelete();
 | 
			
		||||
        $this->quote->forceDelete();
 | 
			
		||||
 | 
			
		||||
        // $migration_file = base_path() . '/tests/Unit/Migration/migration.json';
 | 
			
		||||
 | 
			
		||||
@ -329,6 +327,7 @@ class ImportTest extends TestCase
 | 
			
		||||
    public function testValidityOfImportedData()
 | 
			
		||||
    {
 | 
			
		||||
        $this->invoice->forceDelete();
 | 
			
		||||
        $this->quote->forceDelete();
 | 
			
		||||
 | 
			
		||||
        // $migration_file = base_path() . '/tests/Unit/Migration/migration.json';
 | 
			
		||||
 | 
			
		||||
@ -424,7 +423,7 @@ class ImportTest extends TestCase
 | 
			
		||||
        }*/
 | 
			
		||||
 | 
			
		||||
        foreach ($this->migration_array['documents'] as $key => $document) {
 | 
			
		||||
            $record = Document::whereHash('5a81aa656c8aaf77dca259b7defdda1dc5ae7901')
 | 
			
		||||
            $record = Document::whereHash($document['hash'])
 | 
			
		||||
                ->first();
 | 
			
		||||
 | 
			
		||||
            if (!$record) {
 | 
			
		||||
@ -432,12 +431,14 @@ class ImportTest extends TestCase
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        \Log::error($differences);
 | 
			
		||||
        $this->assertCount(0, $differences);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testClientContactsImport()
 | 
			
		||||
    {
 | 
			
		||||
        $this->invoice->forceDelete();
 | 
			
		||||
        $this->quote->forceDelete();
 | 
			
		||||
 | 
			
		||||
        $original = ClientContact::count();
 | 
			
		||||
 | 
			
		||||
@ -453,6 +454,7 @@ class ImportTest extends TestCase
 | 
			
		||||
    public function testDocumentsImport()
 | 
			
		||||
    {
 | 
			
		||||
        $this->invoice->forceDelete(); 
 | 
			
		||||
        $this->quote->forceDelete();
 | 
			
		||||
 | 
			
		||||
        $original = Document::count();
 | 
			
		||||
 | 
			
		||||
@ -462,6 +464,8 @@ class ImportTest extends TestCase
 | 
			
		||||
 | 
			
		||||
        $document = Document::first();
 | 
			
		||||
        
 | 
			
		||||
\Log::error($document);
 | 
			
		||||
 | 
			
		||||
        $this->assertNotNull(Invoice::find($document->documentable_id)->documents);
 | 
			
		||||
        $this->assertNotNull($document->documentable);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -1,62 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    /* Basic Options */
 | 
			
		||||
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
 | 
			
		||||
    "module": "commonjs",                     /* Specify module code generation: 'none', -> 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
 | 
			
		||||
    // "lib": [],                             /* Specify library files to be included in the compilation. */
 | 
			
		||||
    // "allowJs": true,                       /* Allow javascript files to be compiled. */
 | 
			
		||||
    // "checkJs": true,                       /* Report errors in .js files. */
 | 
			
		||||
    // "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
 | 
			
		||||
    // "declaration": true,                   /* Generates corresponding '.d.ts' file. */
 | 
			
		||||
    // "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
 | 
			
		||||
    "sourceMap": false,                     /* Generates corresponding '.map' file. */
 | 
			
		||||
    // "outFile": "./",                       /* Concatenate and emit output to single file. */
 | 
			
		||||
    // "outDir": "./",                        /* Redirect output structure to the directory. */
 | 
			
		||||
    // "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
 | 
			
		||||
    // "composite": true,                     /* Enable project compilation */
 | 
			
		||||
    // "removeComments": true,                /* Do not emit comments to output. */
 | 
			
		||||
    // "noEmit": true,                        /* Do not emit outputs. */
 | 
			
		||||
    // "importHelpers": true,                 /* Import emit helpers from 'tslib'. */
 | 
			
		||||
    // "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
 | 
			
		||||
    // "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
 | 
			
		||||
 | 
			
		||||
    /* Strict Type-Checking Options */
 | 
			
		||||
    "strict": false,                           /* Enable all strict type-checking options. */
 | 
			
		||||
    "noImplicitAny": false,                 /* Raise error on expressions and declarations with an implied 'any' type. */
 | 
			
		||||
    // "strictNullChecks": true,              /* Enable strict null checks. */
 | 
			
		||||
    // "strictFunctionTypes": true,           /* Enable strict checking of function types. */
 | 
			
		||||
    // "strictPropertyInitialization": true,  /* Enable strict checking of property initialization in classes. */
 | 
			
		||||
    // "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type. */
 | 
			
		||||
    // "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. */
 | 
			
		||||
 | 
			
		||||
    /* Additional Checks */
 | 
			
		||||
    // "noUnusedLocals": true,                /* Report errors on unused locals. */
 | 
			
		||||
    // "noUnusedParameters": true,            /* Report errors on unused parameters. */
 | 
			
		||||
    // "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
 | 
			
		||||
    // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */
 | 
			
		||||
 | 
			
		||||
    /* Module Resolution Options */
 | 
			
		||||
    // "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
 | 
			
		||||
    // "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
 | 
			
		||||
    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
 | 
			
		||||
    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
 | 
			
		||||
    // "typeRoots": [],                       /* List of folders to include type definitions from. */
 | 
			
		||||
    // "types": [],                           /* Type declaration files to be included in compilation. */
 | 
			
		||||
    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
 | 
			
		||||
    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
 | 
			
		||||
    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
 | 
			
		||||
 | 
			
		||||
    /* Source Map Options */
 | 
			
		||||
    // "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */
 | 
			
		||||
    // "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. */
 | 
			
		||||
    // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
 | 
			
		||||
    // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
 | 
			
		||||
 | 
			
		||||
    /* Experimental Options */
 | 
			
		||||
    // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
 | 
			
		||||
    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
 | 
			
		||||
  },
 | 
			
		||||
  "include": [
 | 
			
		||||
    "resources/js/**/*"
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user