mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 14:07:32 -04:00 
			
		
		
		
	
						commit
						b2ee7cce38
					
				
							
								
								
									
										5
									
								
								.github/workflows/phpunit.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/workflows/phpunit.yml
									
									
									
									
										vendored
									
									
								
							| @ -13,7 +13,7 @@ jobs: | |||||||
|     strategy: |     strategy: | ||||||
|       matrix: |       matrix: | ||||||
|         operating-system: ['ubuntu-18.04', 'ubuntu-20.04'] |         operating-system: ['ubuntu-18.04', 'ubuntu-20.04'] | ||||||
|         php-versions: ['7.4','8.0'] |         php-versions: ['7.4','8.0','8.1'] | ||||||
|         phpunit-versions: ['latest'] |         phpunit-versions: ['latest'] | ||||||
| 
 | 
 | ||||||
|     env: |     env: | ||||||
| @ -106,7 +106,8 @@ jobs: | |||||||
|         vendor/bin/phpunit --testdox |         vendor/bin/phpunit --testdox | ||||||
|       env: |       env: | ||||||
|         DB_PORT: ${{ job.services.mysql.ports[3306] }} |         DB_PORT: ${{ job.services.mysql.ports[3306] }} | ||||||
|  |         PHP_CS_FIXER_IGNORE_ENV: true | ||||||
| 
 | 
 | ||||||
|     - name: Run php-cs-fixer |     - name: Run php-cs-fixer | ||||||
|       run: | |       run: | | ||||||
|         vendor/bin/php-cs-fixer fix |         PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix | ||||||
|  | |||||||
| @ -1 +1 @@ | |||||||
| 5.3.33 | 5.3.34 | ||||||
| @ -46,7 +46,14 @@ class CloneQuoteToInvoiceFactory | |||||||
|         $invoice->date = now()->format('Y-m-d'); |         $invoice->date = now()->format('Y-m-d'); | ||||||
|         $invoice->balance = 0; |         $invoice->balance = 0; | ||||||
|         $invoice->deleted_at = null; |         $invoice->deleted_at = null; | ||||||
|          |         $invoice->next_send_date = null; | ||||||
|  |         $invoice->reminder1_sent = null; | ||||||
|  |         $invoice->reminder2_sent = null; | ||||||
|  |         $invoice->reminder3_sent = null; | ||||||
|  |         $invoice->reminder_last_sent = null; | ||||||
|  |         $invoice->last_sent_date = null; | ||||||
|  |         $invoice->last_viewed = null; | ||||||
|  | 
 | ||||||
|         return $invoice; |         return $invoice; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -36,7 +36,7 @@ class ExpenseFilters extends QueryFilters | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return  $this->builder->where(function ($query) use ($filter) { |         return  $this->builder->where(function ($query) use ($filter) { | ||||||
|             $query->where('expenses.name', 'like', '%'.$filter.'%') |             $query->where('expenses.public_notes', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('expenses.id_number', 'like', '%'.$filter.'%') |                           ->orWhere('expenses.id_number', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('expenses.custom_value1', 'like', '%'.$filter.'%') |                           ->orWhere('expenses.custom_value1', 'like', '%'.$filter.'%') | ||||||
|                           ->orWhere('expenses.custom_value2', 'like', '%'.$filter.'%') |                           ->orWhere('expenses.custom_value2', 'like', '%'.$filter.'%') | ||||||
| @ -94,7 +94,10 @@ class ExpenseFilters extends QueryFilters | |||||||
|     { |     { | ||||||
|         $sort_col = explode('|', $sort); |         $sort_col = explode('|', $sort); | ||||||
| 
 | 
 | ||||||
|         return $this->builder->orderBy($sort_col[0], $sort_col[1]); |         if(is_array($sort_col) && in_array($sort_col[1], ['asc', 'desc']) && in_array($sort_col[0], ['public_notes', 'date', 'id_number', 'custom_value1', 'custom_value2', 'custom_value3', 'custom_value4'])) | ||||||
|  |             return $this->builder->orderBy($sort_col[0], $sort_col[1]); | ||||||
|  | 
 | ||||||
|  |         return $this->builder; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -60,8 +60,15 @@ class ContactForgotPasswordController extends Controller | |||||||
|     { |     { | ||||||
|         $account_id = $request->has('account_id') ? $request->get('account_id') : 1; |         $account_id = $request->has('account_id') ? $request->get('account_id') : 1; | ||||||
|         $account = Account::find($account_id); |         $account = Account::find($account_id); | ||||||
|         $company = $account->companies->first(); |  | ||||||
| 
 | 
 | ||||||
|  |         if($request->has('company_key')) | ||||||
|  |             $company = Company::where('company_key', $request->input('company_key'))->first(); | ||||||
|  |         else | ||||||
|  |             $company = $account->companies->first(); | ||||||
|  | 
 | ||||||
|  |         if(!$account) | ||||||
|  |             $account = Account::first(); | ||||||
|  |          | ||||||
|         return $this->render('auth.passwords.request', [ |         return $this->render('auth.passwords.request', [ | ||||||
|             'title' => 'Client Password Reset', |             'title' => 'Client Password Reset', | ||||||
|             'passwordEmailRoute' => 'client.password.email', |             'passwordEmailRoute' => 'client.password.email', | ||||||
| @ -90,7 +97,9 @@ class ContactForgotPasswordController extends Controller | |||||||
| 
 | 
 | ||||||
|         // $user = MultiDB::hasContact($request->input('email'));
 |         // $user = MultiDB::hasContact($request->input('email'));
 | ||||||
|         $company = Company::where('company_key', $request->input('company_key'))->first(); |         $company = Company::where('company_key', $request->input('company_key'))->first(); | ||||||
|         $contact = MultiDB::findContact(['company_id' => $company->id, 'email' => $request->input('email')]); |         //$contact = MultiDB::findContact(['company_id' => $company->id, 'email' => $request->input('email')]);
 | ||||||
|  |         nlog(['company_id' => $company->id, 'email' => $request->input('email')]); | ||||||
|  |         $contact = ClientContact::where(['company_id' => $company->id, 'email' => $request->input('email')])->first(); | ||||||
| 
 | 
 | ||||||
|         $response = false; |         $response = false; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -42,16 +42,15 @@ class ContactLoginController extends Controller | |||||||
| 
 | 
 | ||||||
|         if($request->has('company_key')){ |         if($request->has('company_key')){ | ||||||
|             MultiDB::findAndSetDbByCompanyKey($request->input('company_key')); |             MultiDB::findAndSetDbByCompanyKey($request->input('company_key')); | ||||||
| 
 |  | ||||||
|             $company = Company::where('company_key', $request->input('company_key'))->first(); |             $company = Company::where('company_key', $request->input('company_key'))->first(); | ||||||
| 
 |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (!$company && strpos($request->getHost(), 'invoicing.co') !== false) { |         if($company){ | ||||||
|  |             $account = $company->account; | ||||||
|  |         } | ||||||
|  |         elseif (!$company && strpos($request->getHost(), 'invoicing.co') !== false) { | ||||||
|             $subdomain = explode('.', $request->getHost())[0]; |             $subdomain = explode('.', $request->getHost())[0]; | ||||||
| 
 |  | ||||||
|             MultiDB::findAndSetDbByDomain(['subdomain' => $subdomain]); |             MultiDB::findAndSetDbByDomain(['subdomain' => $subdomain]); | ||||||
| 
 |  | ||||||
|             $company = Company::where('subdomain', $subdomain)->first(); |             $company = Company::where('subdomain', $subdomain)->first(); | ||||||
| 
 | 
 | ||||||
|         } elseif(Ninja::isHosted()){ |         } elseif(Ninja::isHosted()){ | ||||||
| @ -107,7 +106,7 @@ class ContactLoginController extends Controller | |||||||
| 
 | 
 | ||||||
|     public function authenticated(Request $request, ClientContact $client) |     public function authenticated(Request $request, ClientContact $client) | ||||||
|     { |     { | ||||||
|         Auth::guard('contact')->login($client, true); |         Auth::guard('contact')->loginUsingId($client->id, true); | ||||||
| 
 | 
 | ||||||
|         event(new ContactLoggedIn($client, $client->company, Ninja::eventVars())); |         event(new ContactLoggedIn($client, $client->company, Ninja::eventVars())); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -43,7 +43,7 @@ class ContactRegisterController extends Controller | |||||||
|         $client = $this->getClient($request->all()); |         $client = $this->getClient($request->all()); | ||||||
|         $client_contact = $this->getClientContact($request->all(), $client); |         $client_contact = $this->getClientContact($request->all(), $client); | ||||||
| 
 | 
 | ||||||
|         Auth::guard('contact')->login($client_contact, true); |         Auth::guard('contact')->loginUsingId($client_contact->id, true); | ||||||
| 
 | 
 | ||||||
|         return redirect()->route('client.dashboard'); |         return redirect()->route('client.dashboard'); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -255,7 +255,7 @@ class BaseController extends Controller | |||||||
|                   $query->where('expenses.user_id', $user->id)->orWhere('expenses.assigned_user_id', $user->id); |                   $query->where('expenses.user_id', $user->id)->orWhere('expenses.assigned_user_id', $user->id); | ||||||
|             }, |             }, | ||||||
|             'company.groups' => function ($query) use ($updated_at, $user) { |             'company.groups' => function ($query) use ($updated_at, $user) { | ||||||
|                 $query->where('updated_at', '>=', $updated_at)->with('documents'); |                 $query->whereNotNull('updated_at')->with('documents'); | ||||||
| 
 | 
 | ||||||
|                 // if(!$user->isAdmin())
 |                 // if(!$user->isAdmin())
 | ||||||
|                 //   $query->where('group_settings.user_id', $user->id);
 |                 //   $query->where('group_settings.user_id', $user->id);
 | ||||||
| @ -275,7 +275,7 @@ class BaseController extends Controller | |||||||
| 
 | 
 | ||||||
|             }, |             }, | ||||||
|             'company.payment_terms'=> function ($query) use ($updated_at, $user) { |             'company.payment_terms'=> function ($query) use ($updated_at, $user) { | ||||||
|                 $query->where('updated_at', '>=', $updated_at); |                 $query->whereNotNull('updated_at'); | ||||||
| 
 | 
 | ||||||
|                 if(!$user->isAdmin()) |                 if(!$user->isAdmin()) | ||||||
|                   $query->where('payment_terms.user_id', $user->id); |                   $query->where('payment_terms.user_id', $user->id); | ||||||
| @ -346,7 +346,6 @@ class BaseController extends Controller | |||||||
| 
 | 
 | ||||||
|             }, |             }, | ||||||
|             'company.subscriptions'=> function ($query) use($updated_at, $user) { |             'company.subscriptions'=> function ($query) use($updated_at, $user) { | ||||||
|               // $query->where('updated_at', '>=', $updated_at);
 |  | ||||||
|                 $query->whereNotNull('updated_at'); |                 $query->whereNotNull('updated_at'); | ||||||
| 
 | 
 | ||||||
|               if(!$user->isAdmin()) |               if(!$user->isAdmin()) | ||||||
|  | |||||||
| @ -25,7 +25,7 @@ class ContactHashLoginController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function login(string $contact_key) |     public function login(string $contact_key) | ||||||
|     { |     { | ||||||
|         if(request()->has('subscription') && $request->subscription == 'true') { |         if(request()->has('subscription') && request()->subscription == 'true') { | ||||||
| 
 | 
 | ||||||
|             $recurring_invoice = RecurringInvoice::where('client_id', auth()->guard('contact')->client->id) |             $recurring_invoice = RecurringInvoice::where('client_id', auth()->guard('contact')->client->id) | ||||||
|                                                  ->whereNotNull('subscription_id') |                                                  ->whereNotNull('subscription_id') | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ namespace App\Http\Controllers\ClientPortal; | |||||||
| use App\Http\Controllers\Controller; | use App\Http\Controllers\Controller; | ||||||
| use App\Http\Requests\ClientPortal\Documents\ShowDocumentRequest; | use App\Http\Requests\ClientPortal\Documents\ShowDocumentRequest; | ||||||
| use App\Http\Requests\Document\DownloadMultipleDocumentsRequest; | use App\Http\Requests\Document\DownloadMultipleDocumentsRequest; | ||||||
|  | use App\Libraries\MultiDB; | ||||||
| use App\Models\Document; | use App\Models\Document; | ||||||
| use App\Utils\TempFile; | use App\Utils\TempFile; | ||||||
| use App\Utils\Traits\MakesHash; | use App\Utils\Traits\MakesHash; | ||||||
| @ -55,6 +56,8 @@ class DocumentController extends Controller | |||||||
| 
 | 
 | ||||||
|     public function publicDownload(string $document_hash) |     public function publicDownload(string $document_hash) | ||||||
|     { |     { | ||||||
|  |         MultiDB::documentFindAndSetDb($document_hash); | ||||||
|  | 
 | ||||||
|         $document = Document::where('hash', $document_hash)->firstOrFail(); |         $document = Document::where('hash', $document_hash)->firstOrFail(); | ||||||
| 
 | 
 | ||||||
|         $headers = []; |         $headers = []; | ||||||
|  | |||||||
| @ -71,6 +71,8 @@ class InvitationController extends Controller | |||||||
|         if(!in_array($entity, ['invoice', 'credit', 'quote', 'recurring_invoice'])) |         if(!in_array($entity, ['invoice', 'credit', 'quote', 'recurring_invoice'])) | ||||||
|             return response()->json(['message' => 'Invalid resource request']); |             return response()->json(['message' => 'Invalid resource request']); | ||||||
| 
 | 
 | ||||||
|  |         $is_silent = 'false'; | ||||||
|  | 
 | ||||||
|         $key = $entity.'_id'; |         $key = $entity.'_id'; | ||||||
| 
 | 
 | ||||||
|         $entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation'; |         $entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation'; | ||||||
| @ -92,7 +94,7 @@ class InvitationController extends Controller | |||||||
|             $client_contact->email = Str::random(15) . "@example.com"; $client_contact->save(); |             $client_contact->email = Str::random(15) . "@example.com"; $client_contact->save(); | ||||||
| 
 | 
 | ||||||
|         if (request()->has('client_hash') && request()->input('client_hash') == $invitation->contact->client->client_hash) { |         if (request()->has('client_hash') && request()->input('client_hash') == $invitation->contact->client->client_hash) { | ||||||
|             auth()->guard('contact')->login($client_contact, true); |             auth()->guard('contact')->loginUsingId($client_contact->id, true); | ||||||
| 
 | 
 | ||||||
|         } elseif ((bool) $invitation->contact->client->getSetting('enable_client_portal_password') !== false) { |         } elseif ((bool) $invitation->contact->client->getSetting('enable_client_portal_password') !== false) { | ||||||
|             $this->middleware('auth:contact'); |             $this->middleware('auth:contact'); | ||||||
| @ -100,7 +102,7 @@ class InvitationController extends Controller | |||||||
| 
 | 
 | ||||||
|         } else { |         } else { | ||||||
|             nlog("else - default - login contact"); |             nlog("else - default - login contact"); | ||||||
|             auth()->guard('contact')->login($client_contact, true); |             auth()->guard('contact')->loginUsingId($client_contact->id, true); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -111,8 +113,16 @@ class InvitationController extends Controller | |||||||
| 
 | 
 | ||||||
|             $this->fireEntityViewedEvent($invitation, $entity); |             $this->fireEntityViewedEvent($invitation, $entity); | ||||||
|         } |         } | ||||||
|  |         else{ | ||||||
|  |             $is_silent = 'true'; | ||||||
|  | 
 | ||||||
|  |             return redirect()->route('client.'.$entity.'.show', [$entity => $this->encodePrimaryKey($invitation->{$key}), 'silent' => $is_silent]); | ||||||
|  | 
 | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         return redirect()->route('client.'.$entity.'.show', [$entity => $this->encodePrimaryKey($invitation->{$key})]); |         return redirect()->route('client.'.$entity.'.show', [$entity => $this->encodePrimaryKey($invitation->{$key})]); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function fireEntityViewedEvent($invitation, $entity_string) |     private function fireEntityViewedEvent($invitation, $entity_string) | ||||||
| @ -191,7 +201,7 @@ class InvitationController extends Controller | |||||||
|         if($payment->client_id != $contact->client_id) |         if($payment->client_id != $contact->client_id) | ||||||
|             abort(403, 'You are not authorized to view this resource'); |             abort(403, 'You are not authorized to view this resource'); | ||||||
| 
 | 
 | ||||||
|         auth()->guard('contact')->login($contact, true); |         auth()->guard('contact')->loginUsingId($contact->id, true); | ||||||
| 
 | 
 | ||||||
|         return redirect()->route('client.payments.show', $payment->hashed_id); |         return redirect()->route('client.payments.show', $payment->hashed_id); | ||||||
| 
 | 
 | ||||||
| @ -203,7 +213,7 @@ class InvitationController extends Controller | |||||||
|                                     ->with('contact.client') |                                     ->with('contact.client') | ||||||
|                                     ->firstOrFail(); |                                     ->firstOrFail(); | ||||||
|          |          | ||||||
|         auth()->guard('contact')->login($invitation->contact, true); |         auth()->guard('contact')->loginUsingId($invitation->contact->id, true); | ||||||
| 
 | 
 | ||||||
|         $invoice = $invitation->invoice; |         $invoice = $invitation->invoice; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -50,14 +50,17 @@ class NinjaPlanController extends Controller | |||||||
|          |          | ||||||
|             nlog("Ninja Plan Controller - Found and set Client Contact"); |             nlog("Ninja Plan Controller - Found and set Client Contact"); | ||||||
|              |              | ||||||
|             Auth::guard('contact')->login($client_contact,true); |             Auth::guard('contact')->loginUsingId($client_contact->id,true); | ||||||
| 
 | 
 | ||||||
|             /* Current paid users get pushed straight to subscription overview page*/ |             // /* Current paid users get pushed straight to subscription overview page*/
 | ||||||
|             if($account->isPaidHostedClient()) |             // if($account->isPaidHostedClient())
 | ||||||
|                 return redirect('/client/dashboard'); |             //     return redirect('/client/dashboard');
 | ||||||
| 
 | 
 | ||||||
|             /* Users that are not paid get pushed to a custom purchase page */ |             // /* Users that are not paid get pushed to a custom purchase page */
 | ||||||
|             return $this->render('subscriptions.ninja_plan', ['settings' => $client_contact->company->settings]); |             // return $this->render('subscriptions.ninja_plan', ['settings' => $client_contact->company->settings]);
 | ||||||
|  | 
 | ||||||
|  |             return $this->plan(); | ||||||
|  |              | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return redirect()->route('client.catchall'); |         return redirect()->route('client.catchall'); | ||||||
| @ -68,7 +71,8 @@ class NinjaPlanController extends Controller | |||||||
|     { |     { | ||||||
|         //harvest the current plan
 |         //harvest the current plan
 | ||||||
|         $data = []; |         $data = []; | ||||||
| 
 |         $data['late_invoice'] = false; | ||||||
|  |          | ||||||
|         if(MultiDB::findAndSetDbByAccountKey(Auth::guard('contact')->user()->client->custom_value2)) |         if(MultiDB::findAndSetDbByAccountKey(Auth::guard('contact')->user()->client->custom_value2)) | ||||||
|         { |         { | ||||||
|             $account = Account::where('key', Auth::guard('contact')->user()->client->custom_value2)->first(); |             $account = Account::where('key', Auth::guard('contact')->user()->client->custom_value2)->first(); | ||||||
| @ -137,8 +141,7 @@ class NinjaPlanController extends Controller | |||||||
| 
 | 
 | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|             return redirect()->route('client.catchall'); |             return redirect('/client/dashboard'); | ||||||
| 
 |  | ||||||
|              |              | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ class SwitchCompanyController extends Controller | |||||||
|             ->where('id', $this->transformKeys($contact)) |             ->where('id', $this->transformKeys($contact)) | ||||||
|             ->first(); |             ->first(); | ||||||
| 
 | 
 | ||||||
|         auth()->guard('contact')->login($client_contact, true); |         auth()->guard('contact')->loginUsingId($client_contact->id, true); | ||||||
| 
 | 
 | ||||||
|         return redirect('/client/dashboard'); |         return redirect('/client/dashboard'); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -107,7 +107,7 @@ class LicenseController extends BaseController | |||||||
|                         'message' => trans('texts.invalid_white_label_license'), |                         'message' => trans('texts.invalid_white_label_license'), | ||||||
|                         'errors' => new stdClass, |                         'errors' => new stdClass, | ||||||
|                     ]; |                     ]; | ||||||
| 
 |                     $account = auth()->user()->account; | ||||||
|                     $account->plan_term = Account::PLAN_TERM_YEARLY; |                     $account->plan_term = Account::PLAN_TERM_YEARLY; | ||||||
|                     $account->plan_paid = null; |                     $account->plan_paid = null; | ||||||
|                     $account->plan_expires = null; |                     $account->plan_expires = null; | ||||||
| @ -116,7 +116,7 @@ class LicenseController extends BaseController | |||||||
| 
 | 
 | ||||||
|                     return response()->json($error, 400); |                     return response()->json($error, 400); | ||||||
|                 } else { |                 } else { | ||||||
|                     $account = auth()->user()->company()->account; |                     $account = auth()->user()->account; | ||||||
| 
 | 
 | ||||||
|                     $account->plan_term = Account::PLAN_TERM_YEARLY; |                     $account->plan_term = Account::PLAN_TERM_YEARLY; | ||||||
|                     $account->plan_paid = $data; |                     $account->plan_paid = $data; | ||||||
| @ -151,7 +151,7 @@ class LicenseController extends BaseController | |||||||
| 
 | 
 | ||||||
|     private function checkLicense() |     private function checkLicense() | ||||||
|     { |     { | ||||||
|         $account = auth()->user()->company()->account; |         $account = auth()->user()->account; | ||||||
| 
 | 
 | ||||||
|         if($account->plan == 'white_label' && Carbon::parse($account->plan_expires)->lt(now())){ |         if($account->plan == 'white_label' && Carbon::parse($account->plan_expires)->lt(now())){ | ||||||
|             $account->plan = null; |             $account->plan = null; | ||||||
|  | |||||||
| @ -285,7 +285,7 @@ class BillingPortalPurchase extends Component | |||||||
|      */ |      */ | ||||||
|     protected function getPaymentMethods(ClientContact $contact): self |     protected function getPaymentMethods(ClientContact $contact): self | ||||||
|     { |     { | ||||||
|         Auth::guard('contact')->login($contact, true); |         Auth::guard('contact')->loginUsingId($contact->id, true); | ||||||
| 
 | 
 | ||||||
|         $this->contact = $contact; |         $this->contact = $contact; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -74,7 +74,7 @@ class DocumentsTable extends Component | |||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case 'expenses': |             case 'expenses': | ||||||
|                 $this->query = $this->expenses(); |                // $this->query = $this->expenses();
 | ||||||
|                 break; |                 break; | ||||||
| 
 | 
 | ||||||
|             case 'invoices': |             case 'invoices': | ||||||
|  | |||||||
| @ -43,6 +43,7 @@ class InvoicesTable extends Component | |||||||
|         $local_status = []; |         $local_status = []; | ||||||
| 
 | 
 | ||||||
|         $query = Invoice::query() |         $query = Invoice::query() | ||||||
|  |             ->with('client.gateway_tokens','company','client.contacts') | ||||||
|             ->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc') |             ->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc') | ||||||
|             ->where('company_id', $this->company->id) |             ->where('company_id', $this->company->id) | ||||||
|             ->where('is_deleted', false); |             ->where('is_deleted', false); | ||||||
| @ -82,6 +83,7 @@ class InvoicesTable extends Component | |||||||
| 
 | 
 | ||||||
|         return render('components.livewire.invoices-table', [ |         return render('components.livewire.invoices-table', [ | ||||||
|             'invoices' => $query, |             'invoices' => $query, | ||||||
|  |             'gateway_available' => !empty(auth()->user()->client->service()->getPaymentMethods(0)), | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -38,6 +38,7 @@ class QuotesTable extends Component | |||||||
|     public function render() |     public function render() | ||||||
|     { |     { | ||||||
|         $query = Quote::query() |         $query = Quote::query() | ||||||
|  |             ->with('client.gateway_tokens','company','client.contacts') | ||||||
|             ->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc'); |             ->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc'); | ||||||
| 
 | 
 | ||||||
|         if (count($this->status) > 0) { |         if (count($this->status) > 0) { | ||||||
| @ -48,6 +49,7 @@ class QuotesTable extends Component | |||||||
|             ->where('company_id', $this->company->id) |             ->where('company_id', $this->company->id) | ||||||
|             ->where('client_id', auth('contact')->user()->client->id) |             ->where('client_id', auth('contact')->user()->client->id) | ||||||
|             ->where('status_id', '<>', Quote::STATUS_DRAFT) |             ->where('status_id', '<>', Quote::STATUS_DRAFT) | ||||||
|  |             ->where('is_deleted', 0) | ||||||
|             ->withTrashed() |             ->withTrashed() | ||||||
|             ->paginate($this->per_page); |             ->paginate($this->per_page); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -60,7 +60,7 @@ class RequiredClientInfo extends Component | |||||||
| 
 | 
 | ||||||
|         'contact_first_name' => 'first_name', |         'contact_first_name' => 'first_name', | ||||||
|         'contact_last_name' => 'last_name', |         'contact_last_name' => 'last_name', | ||||||
|         // 'contact_email' => 'email',
 |         'contact_email' => 'email', | ||||||
|         // 'contact_phone' => 'phone',
 |         // 'contact_phone' => 'phone',
 | ||||||
|     ]; |     ]; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ class CheckClientExistence | |||||||
|     public function handle(Request $request, Closure $next) |     public function handle(Request $request, Closure $next) | ||||||
|     { |     { | ||||||
|         $multiple_contacts = ClientContact::query() |         $multiple_contacts = ClientContact::query() | ||||||
|             ->with('company','client') |             ->with('client.gateway_tokens') | ||||||
|             ->where('email', auth('contact')->user()->email) |             ->where('email', auth('contact')->user()->email) | ||||||
|             ->whereNotNull('email') |             ->whereNotNull('email') | ||||||
|             ->where('email', '<>', '') |             ->where('email', '<>', '') | ||||||
| @ -52,7 +52,7 @@ class CheckClientExistence | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (count($multiple_contacts) == 1) { |         if (count($multiple_contacts) == 1) { | ||||||
|             Auth::guard('contact')->login($multiple_contacts[0], true); |             Auth::guard('contact')->loginUsingId($multiple_contacts[0]->id, true); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         session()->put('multiple_contacts', $multiple_contacts); |         session()->put('multiple_contacts', $multiple_contacts); | ||||||
|  | |||||||
| @ -52,7 +52,7 @@ class ContactKeyLogin | |||||||
|                  if(empty($client_contact->email)) |                  if(empty($client_contact->email)) | ||||||
|                     $client_contact->email = Str::random(15) . "@example.com"; $client_contact->save(); |                     $client_contact->email = Str::random(15) . "@example.com"; $client_contact->save(); | ||||||
|      |      | ||||||
|                 auth()->guard('contact')->login($client_contact, true); |                 auth()->guard('contact')->loginUsingId($client_contact->id, true); | ||||||
| 
 | 
 | ||||||
|                 if ($request->query('redirect') && !empty($request->query('redirect'))) { |                 if ($request->query('redirect') && !empty($request->query('redirect'))) { | ||||||
|                     return redirect()->to($request->query('redirect')); |                     return redirect()->to($request->query('redirect')); | ||||||
| @ -70,7 +70,7 @@ class ContactKeyLogin | |||||||
|                 if(empty($client_contact->email)) |                 if(empty($client_contact->email)) | ||||||
|                     $client_contact->email = Str::random(6) . "@example.com"; $client_contact->save(); |                     $client_contact->email = Str::random(6) . "@example.com"; $client_contact->save(); | ||||||
| 
 | 
 | ||||||
|                 auth()->guard('contact')->login($client_contact, true); |                 auth()->guard('contact')->loginUsingId($client_contact->id, true); | ||||||
| 
 | 
 | ||||||
|                 if ($request->query('next')) { |                 if ($request->query('next')) { | ||||||
|                     return redirect()->to($request->query('next')); |                     return redirect()->to($request->query('next')); | ||||||
| @ -86,7 +86,7 @@ class ContactKeyLogin | |||||||
|                     $client_contact->email = Str::random(6) . "@example.com"; $client_contact->save(); |                     $client_contact->email = Str::random(6) . "@example.com"; $client_contact->save(); | ||||||
|                 } |                 } | ||||||
|      |      | ||||||
|                 auth()->guard('contact')->login($client_contact, true); |                 auth()->guard('contact')->loginUsingId($client_contact->id, true); | ||||||
| 
 | 
 | ||||||
|                 if ($request->query('next')) { |                 if ($request->query('next')) { | ||||||
|                     return redirect($request->query('next')); |                     return redirect($request->query('next')); | ||||||
| @ -104,7 +104,7 @@ class ContactKeyLogin | |||||||
|                 if(empty($primary_contact->email)) |                 if(empty($primary_contact->email)) | ||||||
|                     $primary_contact->email = Str::random(6) . "@example.com"; $primary_contact->save(); |                     $primary_contact->email = Str::random(6) . "@example.com"; $primary_contact->save(); | ||||||
| 
 | 
 | ||||||
|                     auth()->guard('contact')->login($primary_contact, true); |                     auth()->guard('contact')->loginUsingId($primary_contact->id, true); | ||||||
|                     return redirect()->to('client/dashboard'); |                     return redirect()->to('client/dashboard'); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -116,7 +116,7 @@ class ContactKeyLogin | |||||||
|                 if(empty($primary_contact->email)) |                 if(empty($primary_contact->email)) | ||||||
|                     $primary_contact->email = Str::random(6) . "@example.com"; $primary_contact->save(); |                     $primary_contact->email = Str::random(6) . "@example.com"; $primary_contact->save(); | ||||||
| 
 | 
 | ||||||
|                     auth()->guard('contact')->login($primary_contact, true); |                     auth()->guard('contact')->loginUsingId($primary_contact->id, true); | ||||||
| 
 | 
 | ||||||
|                 return redirect()->to('client/dashboard'); |                 return redirect()->to('client/dashboard'); | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -19,10 +19,11 @@ class ContactRegister | |||||||
|      */ |      */ | ||||||
|     public function handle($request, Closure $next) |     public function handle($request, Closure $next) | ||||||
|     { |     { | ||||||
|  |         $domain_name = $request->getHost(); | ||||||
| 
 | 
 | ||||||
|         if (strpos($request->getHost(), 'invoicing.co') !== false)  |         if (strpos($domain_name, 'invoicing.co') !== false)  | ||||||
|         { |         { | ||||||
|             $subdomain = explode('.', $request->getHost())[0]; |             $subdomain = explode('.', $domain_name)[0]; | ||||||
|              |              | ||||||
|             $query = [ |             $query = [ | ||||||
|                 'subdomain' => $subdomain, |                 'subdomain' => $subdomain, | ||||||
| @ -86,6 +87,6 @@ class ContactRegister | |||||||
|             return $next($request); |             return $next($request); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         abort(404, 'ContactRegister Middlware'); |         abort(404, 'ContactRegister Middleware'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -51,7 +51,7 @@ class ContactTokenAuth | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             //stateless, don't remember the contact.
 |             //stateless, don't remember the contact.
 | ||||||
|             auth()->guard('contact')->login($client_contact, false); |             auth()->guard('contact')->loginUsingId($client_contact->id, false); | ||||||
| 
 | 
 | ||||||
|             event(new ContactLoggedIn($client_contact, $client_contact->company, Ninja::eventVars())); |             event(new ContactLoggedIn($client_contact, $client_contact->company, Ninja::eventVars())); | ||||||
|         } else { |         } else { | ||||||
|  | |||||||
| @ -38,10 +38,11 @@ class SetDomainNameDb | |||||||
|         if(!config('ninja.db.multi_db_enabled')) |         if(!config('ninja.db.multi_db_enabled')) | ||||||
|             return $next($request); |             return $next($request); | ||||||
| 
 | 
 | ||||||
|  |         $domain_name = $request->getHost(); | ||||||
| 
 | 
 | ||||||
|         if (strpos($request->getHost(), 'invoicing.co') !== false)  |         if (strpos($domain_name, 'invoicing.co') !== false)  | ||||||
|         { |         { | ||||||
|             $subdomain = explode('.', $request->getHost())[0]; |             $subdomain = explode('.', $domain_name)[0]; | ||||||
|              |              | ||||||
|             $query = [ |             $query = [ | ||||||
|                 'subdomain' => $subdomain, |                 'subdomain' => $subdomain, | ||||||
| @ -49,7 +50,7 @@ class SetDomainNameDb | |||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             if($company = MultiDB::findAndSetDbByDomain($query)){ |             if($company = MultiDB::findAndSetDbByDomain($query)){ | ||||||
|                 $request->request->add(['account_id' => $company->account_id]); |                 $request->request->add(['account_id' => $company->account_id, 'company_key' => $company->company_key]); | ||||||
|             } |             } | ||||||
|             else  |             else  | ||||||
|             { |             { | ||||||
| @ -71,7 +72,7 @@ class SetDomainNameDb | |||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             if($company = MultiDB::findAndSetDbByDomain($query)){ |             if($company = MultiDB::findAndSetDbByDomain($query)){ | ||||||
|                 $request->request->add(['account_id' => $company->account_id]); |                 $request->request->add(['account_id' => $company->account_id, 'company_key' => $company->company_key]); | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
| @ -86,8 +87,6 @@ class SetDomainNameDb | |||||||
| 
 | 
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // config(['app.url' => $request->getSchemeAndHttpHost()]);
 |  | ||||||
| 
 |  | ||||||
|         return $next($request); |         return $next($request); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,6 +17,7 @@ class ShowPlanSwitchRequest extends FormRequest | |||||||
|      */ |      */ | ||||||
|     public function authorize() |     public function authorize() | ||||||
|     { |     { | ||||||
|  |          | ||||||
|         return (bool)$this->recurring_invoice->subscription->allow_plan_changes; |         return (bool)$this->recurring_invoice->subscription->allow_plan_changes; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -81,6 +81,9 @@ class StoreCompanyRequest extends Request | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if(array_key_exists('portal_domain', $input)) | ||||||
|  |             $input['portal_domain'] = strtolower($input['portal_domain']); | ||||||
|  | 
 | ||||||
|         $this->replace($input); |         $this->replace($input); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -68,8 +68,10 @@ class UpdateCompanyRequest extends Request | |||||||
|     { |     { | ||||||
|         $input = $this->all(); |         $input = $this->all(); | ||||||
| 
 | 
 | ||||||
|         if(Ninja::isHosted() && array_key_exists('portal_domain', $input) && strlen($input['portal_domain']) > 1) |         if(Ninja::isHosted() && array_key_exists('portal_domain', $input) && strlen($input['portal_domain']) > 1){ | ||||||
|             $input['portal_domain'] = $this->addScheme($input['portal_domain']); |             $input['portal_domain'] = $this->addScheme($input['portal_domain']); | ||||||
|  |             $input['portal_domain'] = strtolower($input['portal_domain']); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         if (array_key_exists('settings', $input)) { |         if (array_key_exists('settings', $input)) { | ||||||
|             $input['settings'] = $this->filterSaveableSettings($input['settings']); |             $input['settings'] = $this->filterSaveableSettings($input['settings']); | ||||||
|  | |||||||
| @ -113,7 +113,6 @@ class PortalComposer | |||||||
| 
 | 
 | ||||||
|         $data[] = ['title' => ctrans('texts.payment_methods'), 'url' => 'client.payment_methods.index', 'icon' => 'shield']; |         $data[] = ['title' => ctrans('texts.payment_methods'), 'url' => 'client.payment_methods.index', 'icon' => 'shield']; | ||||||
|         $data[] = ['title' => ctrans('texts.documents'), 'url' => 'client.documents.index', 'icon' => 'download']; |         $data[] = ['title' => ctrans('texts.documents'), 'url' => 'client.documents.index', 'icon' => 'download']; | ||||||
|         $data[] = ['title' => ctrans('texts.subscriptions'), 'url' => 'client.subscriptions.index', 'icon' => 'calendar']; |  | ||||||
| 
 | 
 | ||||||
|         if (auth('contact')->user()->client->getSetting('enable_client_portal_tasks')) { |         if (auth('contact')->user()->client->getSetting('enable_client_portal_tasks')) { | ||||||
|             $data[] = ['title' => ctrans('texts.tasks'), 'url' => 'client.tasks.index', 'icon' => 'clock']; |             $data[] = ['title' => ctrans('texts.tasks'), 'url' => 'client.tasks.index', 'icon' => 'clock']; | ||||||
| @ -123,6 +122,8 @@ class PortalComposer | |||||||
| 
 | 
 | ||||||
|         if(Ninja::isHosted() && auth('contact')->user()->company->id == config('ninja.ninja_default_company_id')) |         if(Ninja::isHosted() && auth('contact')->user()->company->id == config('ninja.ninja_default_company_id')) | ||||||
|             $data[] = ['title' => ctrans('texts.plan'), 'url' => 'client.plan', 'icon' => 'credit-card']; |             $data[] = ['title' => ctrans('texts.plan'), 'url' => 'client.plan', 'icon' => 'credit-card']; | ||||||
|  |         else | ||||||
|  |             $data[] = ['title' => ctrans('texts.subscriptions'), 'url' => 'client.subscriptions.index', 'icon' => 'calendar']; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         return $data; |         return $data; | ||||||
|  | |||||||
| @ -62,20 +62,30 @@ class BaseTransformer | |||||||
|     public function getClient($client_name, $client_email) { |     public function getClient($client_name, $client_email) { | ||||||
| 		$clients = $this->maps['company']->clients; | 		$clients = $this->maps['company']->clients; | ||||||
| 
 | 
 | ||||||
| 		$clients = $clients->where( 'id_number', $client_name ); | 		$client_id_search = $clients->where( 'id_number', $client_name ); | ||||||
| 
 | 
 | ||||||
| 		if ( $clients->count() >= 1 ) { | 		if ( $client_id_search->count() >= 1 ) { | ||||||
| 			return $clients->first()->id; | 			return $client_id_search->first()->id; | ||||||
|  |             nlog("found via id number"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |         $client_name_search = $clients->where( 'name', $client_name ); | ||||||
|  | 
 | ||||||
|  |         if ( $client_name_search->count() >= 1 ) { | ||||||
|  |             return $client_name_search->first()->id; | ||||||
|  |             nlog("found via name"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
| 		if ( ! empty( $client_email ) ) { | 		if ( ! empty( $client_email ) ) { | ||||||
| 			$contacts = ClientContact::where( 'company_id', $this->maps['company']->id ) | 			$contacts = ClientContact::where( 'company_id', $this->maps['company']->id ) | ||||||
| 									 ->where( 'email', $client_email ); | 									 ->where( 'email', $client_email ); | ||||||
| 
 | 
 | ||||||
| 			if ( $contacts->count() >= 1 ) { | 			if ( $contacts->count() >= 1 ) { | ||||||
| 				return $contacts->first()->client_id; | 				return $contacts->first()->client_id; | ||||||
|  | nlog("found via contact"); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | nlog("did not find client"); | ||||||
| 
 | 
 | ||||||
| 		return null; | 		return null; | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -49,7 +49,7 @@ class InvoiceTransformer extends BaseTransformer { | |||||||
| 			'due_date'          => isset( $invoice_data['invoice.due_date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['invoice.due_date'] ) ) : null, | 			'due_date'          => isset( $invoice_data['invoice.due_date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['invoice.due_date'] ) ) : null, | ||||||
| 			'terms'             => $this->getString( $invoice_data, 'invoice.terms' ), | 			'terms'             => $this->getString( $invoice_data, 'invoice.terms' ), | ||||||
| 			'public_notes'      => $this->getString( $invoice_data, 'invoice.public_notes' ), | 			'public_notes'      => $this->getString( $invoice_data, 'invoice.public_notes' ), | ||||||
| 			'is_sent'           => $this->getString( $invoice_data, 'invoice.is_sent' ), | 			// 'is_sent'           => $this->getString( $invoice_data, 'invoice.is_sent' ),
 | ||||||
| 			'private_notes'     => $this->getString( $invoice_data, 'invoice.private_notes' ), | 			'private_notes'     => $this->getString( $invoice_data, 'invoice.private_notes' ), | ||||||
| 			'tax_name1'         => $this->getString( $invoice_data, 'invoice.tax_name1' ), | 			'tax_name1'         => $this->getString( $invoice_data, 'invoice.tax_name1' ), | ||||||
| 			'tax_rate1'         => $this->getFloat( $invoice_data, 'invoice.tax_rate1' ), | 			'tax_rate1'         => $this->getFloat( $invoice_data, 'invoice.tax_rate1' ), | ||||||
| @ -92,7 +92,7 @@ class InvoiceTransformer extends BaseTransformer { | |||||||
| 					'amount'                => $this->getFloat( $invoice_data, 'invoice.amount' ), | 					'amount'                => $this->getFloat( $invoice_data, 'invoice.amount' ), | ||||||
| 				], | 				], | ||||||
| 			]; | 			]; | ||||||
| 		} elseif ( isset( $transformed['amount'] ) && isset( $transformed['balance'] ) ) { | 		} elseif ( isset( $transformed['amount'] ) && isset( $transformed['balance'] ) && ($transformed['amount'] != $transformed['balance'])) { | ||||||
| 			$transformed['payments'] = [ | 			$transformed['payments'] = [ | ||||||
| 				[ | 				[ | ||||||
| 					'date'                  => isset( $invoice_data['payment.date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['payment.date'] ) ) : date( 'y-m-d' ), | 					'date'                  => isset( $invoice_data['payment.date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['payment.date'] ) ) : date( 'y-m-d' ), | ||||||
| @ -126,6 +126,8 @@ class InvoiceTransformer extends BaseTransformer { | |||||||
| 		} | 		} | ||||||
| 		$transformed['line_items'] = $line_items; | 		$transformed['line_items'] = $line_items; | ||||||
| 
 | 
 | ||||||
|  | nlog($transformed); | ||||||
|  | 
 | ||||||
| 		return $transformed; | 		return $transformed; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -53,7 +53,7 @@ class AutoBill | |||||||
|              |              | ||||||
|             nlog("autobill {$this->invoice->id}"); |             nlog("autobill {$this->invoice->id}"); | ||||||
| 
 | 
 | ||||||
|             $this->invoice->service()->autoBill()->save(); |             $this->invoice->service()->autoBill(); | ||||||
| 
 | 
 | ||||||
|         } |         } | ||||||
|         catch(\Exception $e) { |         catch(\Exception $e) { | ||||||
|  | |||||||
| @ -115,9 +115,6 @@ class CreateEntityPdf implements ShouldQueue | |||||||
|         /* Set customized translations _NOW_ */ |         /* Set customized translations _NOW_ */ | ||||||
|         $t->replace(Ninja::transformTranslations($this->client->getMergedSettings())); |         $t->replace(Ninja::transformTranslations($this->client->getMergedSettings())); | ||||||
| 
 | 
 | ||||||
|         $translate = microtime(true); |  | ||||||
|         // nlog("Translate ". $translate - $start);
 |  | ||||||
| 
 |  | ||||||
|         if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') { |         if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') { | ||||||
|             return (new Phantom)->generate($this->invitation); |             return (new Phantom)->generate($this->invitation); | ||||||
|         } |         } | ||||||
| @ -142,9 +139,6 @@ class CreateEntityPdf implements ShouldQueue | |||||||
| 
 | 
 | ||||||
|         $entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->client->getSetting($entity_design_id)); |         $entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->client->getSetting($entity_design_id)); | ||||||
| 
 | 
 | ||||||
|         // if(!$this->company->account->hasFeature(Account::FEATURE_DIFFERENT_DESIGNS))
 |  | ||||||
|         //     $entity_design_id = 2;
 |  | ||||||
| 
 |  | ||||||
|         $design = Design::find($entity_design_id); |         $design = Design::find($entity_design_id); | ||||||
| 
 | 
 | ||||||
|         /* Catch all in case migration doesn't pass back a valid design */ |         /* Catch all in case migration doesn't pass back a valid design */ | ||||||
| @ -153,9 +147,6 @@ class CreateEntityPdf implements ShouldQueue | |||||||
| 
 | 
 | ||||||
|         $html = new HtmlEngine($this->invitation); |         $html = new HtmlEngine($this->invitation); | ||||||
| 
 | 
 | ||||||
|         $design_time = microtime(true); |  | ||||||
|         // nlog("Design ". $design_time - $translate);
 |  | ||||||
| 
 |  | ||||||
|         if ($design->is_custom) { |         if ($design->is_custom) { | ||||||
|             $options = [ |             $options = [ | ||||||
|             'custom_partials' => json_decode(json_encode($design->design), true) |             'custom_partials' => json_decode(json_encode($design->design), true) | ||||||
| @ -167,9 +158,6 @@ class CreateEntityPdf implements ShouldQueue | |||||||
| 
 | 
 | ||||||
|         $variables = $html->generateLabelsAndValues(); |         $variables = $html->generateLabelsAndValues(); | ||||||
| 
 | 
 | ||||||
|         $labels_time = microtime(true); |  | ||||||
|         // nlog("Labels ". $labels_time - $design_time);
 |  | ||||||
| 
 |  | ||||||
|         $state = [ |         $state = [ | ||||||
|             'template' => $template->elements([ |             'template' => $template->elements([ | ||||||
|                 'client' => $this->client, |                 'client' => $this->client, | ||||||
| @ -192,10 +180,6 @@ class CreateEntityPdf implements ShouldQueue | |||||||
|             ->design($template) |             ->design($template) | ||||||
|             ->build(); |             ->build(); | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         $template_time = microtime(true); |  | ||||||
|         // nlog("Template Build ". $template_time - $labels_time);
 |  | ||||||
| 
 |  | ||||||
|         $pdf = null; |         $pdf = null; | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
| @ -215,10 +199,6 @@ class CreateEntityPdf implements ShouldQueue | |||||||
|             info($maker->getCompiledHTML()); |             info($maker->getCompiledHTML()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         $pdf_time = microtime(true); |  | ||||||
|         // nlog("PDF time " . $pdf_time - $template_time);
 |  | ||||||
| 
 |  | ||||||
|         if ($pdf) { |         if ($pdf) { | ||||||
| 
 | 
 | ||||||
|             try{ |             try{ | ||||||
|  | |||||||
| @ -188,9 +188,9 @@ class CreateRawPdf implements ShouldQueue | |||||||
|             nlog(print_r($e->getMessage(), 1)); |             nlog(print_r($e->getMessage(), 1)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // if (config('ninja.log_pdf_html')) {
 |         if (config('ninja.log_pdf_html')) { | ||||||
|             info($maker->getCompiledHTML()); |             info($maker->getCompiledHTML()); | ||||||
|         // }
 |         } | ||||||
| 
 | 
 | ||||||
|         if ($pdf)  |         if ($pdf)  | ||||||
|             return $pdf; |             return $pdf; | ||||||
|  | |||||||
| @ -112,6 +112,9 @@ class EmailEntity implements ShouldQueue | |||||||
|         App::setLocale($this->invitation->contact->preferredLocale()); |         App::setLocale($this->invitation->contact->preferredLocale()); | ||||||
|         $t->replace(Ninja::transformTranslations($this->settings)); |         $t->replace(Ninja::transformTranslations($this->settings)); | ||||||
| 
 | 
 | ||||||
|  |         /* Mark entity sent */ | ||||||
|  |         $this->entity->service()->markSent()->save(); | ||||||
|  |          | ||||||
|         $nmo = new NinjaMailerObject; |         $nmo = new NinjaMailerObject; | ||||||
|         $nmo->mailable = new TemplateEmail($this->email_entity_builder, $this->invitation->contact, $this->invitation); |         $nmo->mailable = new TemplateEmail($this->email_entity_builder, $this->invitation->contact, $this->invitation); | ||||||
|         $nmo->company = $this->company; |         $nmo->company = $this->company; | ||||||
| @ -124,8 +127,7 @@ class EmailEntity implements ShouldQueue | |||||||
|          |          | ||||||
|         NinjaMailerJob::dispatchNow($nmo); |         NinjaMailerJob::dispatchNow($nmo); | ||||||
| 
 | 
 | ||||||
|         /* Mark entity sent */ | 
 | ||||||
|         $this->entity->service()->markSent()->save(); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function resolveEntityString() :string |     private function resolveEntityString() :string | ||||||
|  | |||||||
| @ -332,18 +332,21 @@ class CSVImport implements ShouldQueue { | |||||||
| 			$invoice = $invoice->service()->markViewed()->save(); | 			$invoice = $invoice->service()->markViewed()->save(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if ( $invoice->status_id === Invoice::STATUS_SENT ) { | 		if( $invoice->status_id === Invoice::STATUS_DRAFT ){ | ||||||
|  | 
 | ||||||
|  | 		} | ||||||
|  | 		elseif ( $invoice->status_id === Invoice::STATUS_SENT ) { | ||||||
| 			$invoice = $invoice->service()->markSent()->save(); | 			$invoice = $invoice->service()->markSent()->save(); | ||||||
| 		} | 		} | ||||||
| 
 | 		elseif ( $invoice->status_id <= Invoice::STATUS_SENT && $invoice->amount > 0 ) { | ||||||
| 		if ( $invoice->status_id <= Invoice::STATUS_SENT && $invoice->amount > 0 ) { | 			if ( $invoice->balance <= 0 ) { | ||||||
| 			if ( $invoice->balance < $invoice->amount ) { |  | ||||||
| 				$invoice->status_id = Invoice::STATUS_PARTIAL; |  | ||||||
| 				$invoice->save(); |  | ||||||
| 			} elseif ( $invoice->balance <= 0 ) { |  | ||||||
| 				$invoice->status_id = Invoice::STATUS_PAID; | 				$invoice->status_id = Invoice::STATUS_PAID; | ||||||
| 				$invoice->save(); | 				$invoice->save(); | ||||||
| 			} | 			} | ||||||
|  | 			elseif ( $invoice->balance != $invoice->amount ) { | ||||||
|  | 				$invoice->status_id = Invoice::STATUS_PARTIAL; | ||||||
|  | 				$invoice->save(); | ||||||
|  | 			}  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -20,8 +20,10 @@ use App\Mail\Admin\EntityNotificationMailer; | |||||||
| use App\Mail\Admin\PaymentFailureObject; | use App\Mail\Admin\PaymentFailureObject; | ||||||
| use App\Models\Client; | use App\Models\Client; | ||||||
| use App\Models\Company; | use App\Models\Company; | ||||||
|  | use App\Models\Invoice; | ||||||
| use App\Models\PaymentHash; | use App\Models\PaymentHash; | ||||||
| use App\Models\User; | use App\Models\User; | ||||||
|  | use App\Utils\Traits\MakesHash; | ||||||
| use App\Utils\Traits\Notifications\UserNotifies; | use App\Utils\Traits\Notifications\UserNotifies; | ||||||
| use Illuminate\Bus\Queueable; | use Illuminate\Bus\Queueable; | ||||||
| use Illuminate\Contracts\Queue\ShouldQueue; | use Illuminate\Contracts\Queue\ShouldQueue; | ||||||
| @ -34,7 +36,7 @@ use Illuminate\Support\Facades\Mail; | |||||||
| 
 | 
 | ||||||
| class PaymentFailedMailer implements ShouldQueue | class PaymentFailedMailer implements ShouldQueue | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, UserNotifies; |     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, UserNotifies, MakesHash; | ||||||
| 
 | 
 | ||||||
|     public ?PaymentHash $payment_hash; |     public ?PaymentHash $payment_hash; | ||||||
| 
 | 
 | ||||||
| @ -75,15 +77,17 @@ class PaymentFailedMailer implements ShouldQueue | |||||||
| 
 | 
 | ||||||
|         $settings = $this->client->getMergedSettings(); |         $settings = $this->client->getMergedSettings(); | ||||||
|         $amount = 0; |         $amount = 0; | ||||||
|  |         $invoice = false; | ||||||
| 
 | 
 | ||||||
|         if($this->payment_hash) |         if($this->payment_hash){ | ||||||
|             $amount = array_sum(array_column($this->payment_hash->invoices(), 'amount')) + $this->payment_hash->fee_total; |             $amount = array_sum(array_column($this->payment_hash->invoices(), 'amount')) + $this->payment_hash->fee_total; | ||||||
|  |             $invoice = Invoice::whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->first(); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         //iterate through company_users
 |         //iterate through company_users
 | ||||||
|         $this->company->company_users->each(function ($company_user) use($amount, $settings){         |         $this->company->company_users->each(function ($company_user) use($amount, $settings, $invoice){         | ||||||
| 
 | 
 | ||||||
|             //determine if this user has the right permissions
 |             $methods = $this->findUserEntityNotificationType($invoice ?: $this->client, $company_user, ['payment_failure_user', 'payment_failure_all', 'payment_failure', 'all_notifications']); | ||||||
|             $methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure','all_notifications']); |  | ||||||
| 
 | 
 | ||||||
|             //if mail is a method type -fire mail!!
 |             //if mail is a method type -fire mail!!
 | ||||||
|             if (($key = array_search('mail', $methods)) !== false) { |             if (($key = array_search('mail', $methods)) !== false) { | ||||||
|  | |||||||
| @ -80,7 +80,7 @@ class PaymentFailureMailer implements ShouldQueue | |||||||
|         $this->company->company_users->each(function ($company_user) {         |         $this->company->company_users->each(function ($company_user) {         | ||||||
| 
 | 
 | ||||||
|             //determine if this user has the right permissions
 |             //determine if this user has the right permissions
 | ||||||
|             $methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure','all_notifications']); |             $methods = $this->findCompanyUserNotificationType($company_user, ['payment_failure_all','payment_failure', 'payment_failure_user', 'all_notifications']); | ||||||
| 
 | 
 | ||||||
|             //if mail is a method type -fire mail!!
 |             //if mail is a method type -fire mail!!
 | ||||||
|             if (($key = array_search('mail', $methods)) !== false) { |             if (($key = array_search('mail', $methods)) !== false) { | ||||||
|  | |||||||
| @ -145,7 +145,7 @@ class SendRecurring implements ShouldQueue | |||||||
|      |      | ||||||
|         if ($invoice->client->getSetting('auto_bill_date') == 'on_send_date' && $invoice->auto_bill_enabled) { |         if ($invoice->client->getSetting('auto_bill_date') == 'on_send_date' && $invoice->auto_bill_enabled) { | ||||||
|             nlog("attempting to autobill {$invoice->number}"); |             nlog("attempting to autobill {$invoice->number}"); | ||||||
|             $invoice->service()->autoBill()->save(); |             $invoice->service()->autoBill(); | ||||||
| 
 | 
 | ||||||
|         } |         } | ||||||
|         elseif($invoice->client->getSetting('auto_bill_date') == 'on_due_date' && $invoice->auto_bill_enabled) { |         elseif($invoice->client->getSetting('auto_bill_date') == 'on_due_date' && $invoice->auto_bill_enabled) { | ||||||
| @ -153,7 +153,7 @@ class SendRecurring implements ShouldQueue | |||||||
|             if($invoice->due_date && Carbon::parse($invoice->due_date)->startOfDay()->lte(now()->startOfDay())) { |             if($invoice->due_date && Carbon::parse($invoice->due_date)->startOfDay()->lte(now()->startOfDay())) { | ||||||
|              |              | ||||||
|                 nlog("attempting to autobill {$invoice->number}"); |                 nlog("attempting to autobill {$invoice->number}"); | ||||||
|                 $invoice->service()->autoBill()->save(); |                 $invoice->service()->autoBill(); | ||||||
|              |              | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -59,7 +59,12 @@ class PaymentNotification implements ShouldQueue | |||||||
|         foreach ($payment->company->company_users as $company_user) { |         foreach ($payment->company->company_users as $company_user) { | ||||||
|             $user = $company_user->user; |             $user = $company_user->user; | ||||||
| 
 | 
 | ||||||
|             $methods = $this->findUserEntityNotificationType($payment, $company_user, ['payment_success', 'payment_success_all', 'all_notifications']); |             $methods = $this->findUserEntityNotificationType($payment, $company_user, [ | ||||||
|  |                 'payment_success',  | ||||||
|  |                 'payment_success_all',  | ||||||
|  |                 'payment_success_user',  | ||||||
|  |                 'all_notifications'] | ||||||
|  |             ); | ||||||
| 
 | 
 | ||||||
|             if (($key = array_search('mail', $methods)) !== false) { |             if (($key = array_search('mail', $methods)) !== false) { | ||||||
|                 unset($methods[$key]); |                 unset($methods[$key]); | ||||||
|  | |||||||
| @ -69,6 +69,9 @@ class CreditEmailEngine extends BaseEmailEngine | |||||||
|                 null, |                 null, | ||||||
|                 $this->client->locale() |                 $this->client->locale() | ||||||
|             ); |             ); | ||||||
|  | 
 | ||||||
|  |             $body_template .= '<div class="center">$view_button</div>'; | ||||||
|  | 
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (is_array($this->template_data) &&  array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0) { |         if (is_array($this->template_data) &&  array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0) { | ||||||
|  | |||||||
| @ -74,6 +74,9 @@ class InvoiceEmailEngine extends BaseEmailEngine | |||||||
|                 null, |                 null, | ||||||
|                 $this->client->locale() |                 $this->client->locale() | ||||||
|             ); |             ); | ||||||
|  | 
 | ||||||
|  |             $body_template .= '<div class="center">$view_button</div>'; | ||||||
|  | 
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (is_array($this->template_data) &&  array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0) { |         if (is_array($this->template_data) &&  array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0) { | ||||||
|  | |||||||
| @ -44,6 +44,7 @@ class QuoteEmailEngine extends BaseEmailEngine | |||||||
| 
 | 
 | ||||||
|     public function build() |     public function build() | ||||||
|     { |     { | ||||||
|  | 
 | ||||||
|         App::forgetInstance('translator'); |         App::forgetInstance('translator'); | ||||||
|         $t = app('translator'); |         $t = app('translator'); | ||||||
|         $t->replace(Ninja::transformTranslations($this->client->getMergedSettings())); |         $t->replace(Ninja::transformTranslations($this->client->getMergedSettings())); | ||||||
| @ -56,21 +57,25 @@ class QuoteEmailEngine extends BaseEmailEngine | |||||||
|         } else { |         } else { | ||||||
|             $body_template = $this->client->getSetting('email_template_'.$this->reminder_template); |             $body_template = $this->client->getSetting('email_template_'.$this->reminder_template); | ||||||
|         } |         } | ||||||
|          | 
 | ||||||
|         /* Use default translations if a custom message has not been set*/ |         /* Use default translations if a custom message has not been set*/ | ||||||
|         if (iconv_strlen($body_template) == 0) { |         if (iconv_strlen($body_template) == 0) { | ||||||
|  | 
 | ||||||
|             $body_template = trans( |             $body_template = trans( | ||||||
|                 'texts.quote_message', |                 'texts.quote_message', | ||||||
|                 [ |                 [ | ||||||
|                     'quote' => $this->quote->number, |                     'quote' => $this->quote->number, | ||||||
|                     'company' => $this->quote->company->present()->name(), |                     'company' => $this->quote->company->present()->name(), | ||||||
|                     'amount' => Number::formatMoney($this->quote->balance, $this->client), |                     'amount' => Number::formatMoney($this->quote->amount, $this->client), | ||||||
|                 ], |                 ], | ||||||
|                 null, |                 null, | ||||||
|                 $this->client->locale() |                 $this->client->locale() | ||||||
|             ); |             ); | ||||||
|  | 
 | ||||||
|  |             $body_template .= '<div class="center">$view_button</div>'; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|         if (is_array($this->template_data) &&  array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0) { |         if (is_array($this->template_data) &&  array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0) { | ||||||
|             $subject_template = $this->template_data['subject']; |             $subject_template = $this->template_data['subject']; | ||||||
|         } else { |         } else { | ||||||
| @ -99,7 +104,6 @@ class QuoteEmailEngine extends BaseEmailEngine | |||||||
|             ->setViewText(ctrans('texts.view_quote')) |             ->setViewText(ctrans('texts.view_quote')) | ||||||
|             ->setInvitation($this->invitation); |             ->setInvitation($this->invitation); | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         if ($this->client->getSetting('pdf_email_attachment') !== false && $this->quote->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { |         if ($this->client->getSetting('pdf_email_attachment') !== false && $this->quote->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { | ||||||
| 
 | 
 | ||||||
|             if(Ninja::isHosted()) |             if(Ninja::isHosted()) | ||||||
|  | |||||||
| @ -52,7 +52,8 @@ class TemplateEmail extends Mailable | |||||||
| 
 | 
 | ||||||
|     public function build() |     public function build() | ||||||
|     { |     { | ||||||
|          $template_name = 'email.template.'.$this->build_email->getTemplate(); |          | ||||||
|  |         $template_name = 'email.template.'.$this->build_email->getTemplate(); | ||||||
| 
 | 
 | ||||||
|         if ($this->build_email->getTemplate() == 'light' || $this->build_email->getTemplate() == 'dark') { |         if ($this->build_email->getTemplate() == 'light' || $this->build_email->getTemplate() == 'dark') { | ||||||
|             $template_name = 'email.template.client'; |             $template_name = 'email.template.client'; | ||||||
|  | |||||||
| @ -75,6 +75,7 @@ class Quote extends BaseModel | |||||||
|         'assigned_user_id', |         'assigned_user_id', | ||||||
|         'exchange_rate', |         'exchange_rate', | ||||||
|         'subscription_id', |         'subscription_id', | ||||||
|  |         'uses_inclusive_taxes', | ||||||
|     ]; |     ]; | ||||||
| 
 | 
 | ||||||
|     protected $casts = [ |     protected $casts = [ | ||||||
|  | |||||||
| @ -30,6 +30,7 @@ use App\Models\GatewayType; | |||||||
| use App\Models\Invoice; | use App\Models\Invoice; | ||||||
| use App\Models\Payment; | use App\Models\Payment; | ||||||
| use App\Models\PaymentHash; | use App\Models\PaymentHash; | ||||||
|  | use App\Models\PaymentType; | ||||||
| use App\Models\SystemLog; | use App\Models\SystemLog; | ||||||
| use App\Services\Subscription\SubscriptionService; | use App\Services\Subscription\SubscriptionService; | ||||||
| use App\Utils\Ninja; | use App\Utils\Ninja; | ||||||
| @ -262,12 +263,18 @@ class BaseDriver extends AbstractPaymentDriver | |||||||
| 
 | 
 | ||||||
|         event('eloquent.created: App\Models\Payment', $payment); |         event('eloquent.created: App\Models\Payment', $payment); | ||||||
| 
 | 
 | ||||||
|         if ($this->client->getSetting('client_online_payment_notification')) |         if ($this->client->getSetting('client_online_payment_notification') && in_array($status, [Payment::STATUS_COMPLETED, Payment::STATUS_PENDING | ||||||
|  |         ])) | ||||||
|             $payment->service()->sendEmail(); |             $payment->service()->sendEmail(); | ||||||
| 
 | 
 | ||||||
|  |             //todo
 | ||||||
|  |             //catch any payment failures here also and fire a subsequent failure email if necessary? note only need for delayed payment forms
 | ||||||
|  |             //perhaps this type of functionality should be handled higher up to provide better context?
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|         event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars())); |         event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars())); | ||||||
| 
 | 
 | ||||||
|         if (property_exists($this->payment_hash->data, 'billing_context')) { |         if (property_exists($this->payment_hash->data, 'billing_context') && $status == Payment::STATUS_COMPLETED) { | ||||||
|             $billing_subscription = \App\Models\Subscription::find($this->payment_hash->data->billing_context->subscription_id); |             $billing_subscription = \App\Models\Subscription::find($this->payment_hash->data->billing_context->subscription_id); | ||||||
| 
 | 
 | ||||||
|             // To access campaign hash => $this->payment_hash->data->billing_context->campaign;
 |             // To access campaign hash => $this->payment_hash->data->billing_context->campaign;
 | ||||||
| @ -440,7 +447,7 @@ class BaseDriver extends AbstractPaymentDriver | |||||||
| 
 | 
 | ||||||
|             $invoices->first()->invitations->each(function ($invitation) use ($nmo) { |             $invoices->first()->invitations->each(function ($invitation) use ($nmo) { | ||||||
| 
 | 
 | ||||||
|                 if ($invitation->contact->email) { |                 if ((bool)$invitation->contact->send_email !== false && $invitation->contact->email) { | ||||||
| 
 | 
 | ||||||
|                     $nmo->to_user = $invitation->contact; |                     $nmo->to_user = $invitation->contact; | ||||||
|                     NinjaMailerJob::dispatch($nmo); |                     NinjaMailerJob::dispatch($nmo); | ||||||
|  | |||||||
| @ -161,7 +161,8 @@ class PayPal | |||||||
|             SystemLog::CATEGORY_GATEWAY_RESPONSE, |             SystemLog::CATEGORY_GATEWAY_RESPONSE, | ||||||
|             SystemLog::EVENT_GATEWAY_FAILURE, |             SystemLog::EVENT_GATEWAY_FAILURE, | ||||||
|             SystemLog::TYPE_BRAINTREE, |             SystemLog::TYPE_BRAINTREE, | ||||||
|             $this->braintree->client |             $this->braintree->client, | ||||||
|  |             $this->braintree->client->company | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         throw new PaymentFailed($response->message, 0); |         throw new PaymentFailed($response->message, 0); | ||||||
|  | |||||||
| @ -213,10 +213,10 @@ class CreditCard implements MethodInterface | |||||||
|             if ($response->status == 'Declined') { |             if ($response->status == 'Declined') { | ||||||
|                 $this->checkout->unWindGatewayFees($this->checkout->payment_hash); |                 $this->checkout->unWindGatewayFees($this->checkout->payment_hash); | ||||||
| 
 | 
 | ||||||
|                 $this->checkout->sendFailureMail($response->response_summary); |                 // $this->checkout->sendFailureMail($response->response_summary);
 | ||||||
| 
 |                  | ||||||
|                 //@todo - this will double up the checkout . com failed mails
 |                 //@todo - this will double up the checkout . com failed mails
 | ||||||
|                 $this->checkout->clientPaymentFailureMailer($response->status); |                 // $this->checkout->clientPaymentFailureMailer($response->status);
 | ||||||
|                  |                  | ||||||
|                 return $this->processUnsuccessfulPayment($response); |                 return $this->processUnsuccessfulPayment($response); | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -84,8 +84,9 @@ trait Utilities | |||||||
| 
 | 
 | ||||||
|     public function processUnsuccessfulPayment(Payment $_payment, $throw_exception = true) |     public function processUnsuccessfulPayment(Payment $_payment, $throw_exception = true) | ||||||
|     { |     { | ||||||
|         $this->getParent()->sendFailureMail($_payment->status . " " . optional($_payment)->response_summary); |         $this->getParent()->sendFailureMail($_payment->response_summary); | ||||||
| 
 |         // $this->getParent()->clientPaymentFailureMailer($_payment->status);
 | ||||||
|  |                  | ||||||
|         $message = [ |         $message = [ | ||||||
|             'server_response' => $_payment, |             'server_response' => $_payment, | ||||||
|             'data' => $this->getParent()->payment_hash->data, |             'data' => $this->getParent()->payment_hash->data, | ||||||
|  | |||||||
| @ -160,11 +160,11 @@ class ACH implements MethodInterface | |||||||
|      */ |      */ | ||||||
|     public function paymentResponse(PaymentResponseRequest $request) |     public function paymentResponse(PaymentResponseRequest $request) | ||||||
|     { |     { | ||||||
|         $token = ClientGatewayToken::find( |         // $token = ClientGatewayToken::find(
 | ||||||
|             $this->decodePrimaryKey($request->source) |         //     $this->decodePrimaryKey($request->source)
 | ||||||
|         )->firstOrFail(); |         // )->firstOrFail();
 | ||||||
| 
 | 
 | ||||||
|         $this->go_cardless->ensureMandateIsReady($token); |         $this->go_cardless->ensureMandateIsReady($request->source); | ||||||
|              |              | ||||||
|         try { |         try { | ||||||
|             $payment = $this->go_cardless->gateway->payments()->create([ |             $payment = $this->go_cardless->gateway->payments()->create([ | ||||||
| @ -175,7 +175,7 @@ class ACH implements MethodInterface | |||||||
|                         'payment_hash' => $this->go_cardless->payment_hash->hash, |                         'payment_hash' => $this->go_cardless->payment_hash->hash, | ||||||
|                     ], |                     ], | ||||||
|                     'links' => [ |                     'links' => [ | ||||||
|                         'mandate' => $token->token, |                         'mandate' => $request->source, | ||||||
|                     ], |                     ], | ||||||
|                 ], |                 ], | ||||||
|             ]); |             ]); | ||||||
| @ -201,7 +201,6 @@ class ACH implements MethodInterface | |||||||
|     public function processPendingPayment(\GoCardlessPro\Resources\Payment $payment, array $data = []) |     public function processPendingPayment(\GoCardlessPro\Resources\Payment $payment, array $data = []) | ||||||
|     { |     { | ||||||
|         $data = [ |         $data = [ | ||||||
|             'payment_method' => $data['token'], |  | ||||||
|             'payment_type' => PaymentType::ACH, |             'payment_type' => PaymentType::ACH, | ||||||
|             'amount' => $this->go_cardless->payment_hash->data->amount_with_fee, |             'amount' => $this->go_cardless->payment_hash->data->amount_with_fee, | ||||||
|             'transaction_reference' => $payment->id, |             'transaction_reference' => $payment->id, | ||||||
|  | |||||||
| @ -152,11 +152,8 @@ class DirectDebit implements MethodInterface | |||||||
| 
 | 
 | ||||||
|     public function paymentResponse(PaymentResponseRequest $request) |     public function paymentResponse(PaymentResponseRequest $request) | ||||||
|     { |     { | ||||||
|         $token = ClientGatewayToken::find( |  | ||||||
|             $this->decodePrimaryKey($request->source) |  | ||||||
|         )->firstOrFail(); |  | ||||||
| 
 | 
 | ||||||
|         $this->go_cardless->ensureMandateIsReady($token); |         $this->go_cardless->ensureMandateIsReady($request->source); | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|             $payment = $this->go_cardless->gateway->payments()->create([ |             $payment = $this->go_cardless->gateway->payments()->create([ | ||||||
| @ -167,14 +164,14 @@ class DirectDebit implements MethodInterface | |||||||
|                         'payment_hash' => $this->go_cardless->payment_hash->hash, |                         'payment_hash' => $this->go_cardless->payment_hash->hash, | ||||||
|                     ], |                     ], | ||||||
|                     'links' => [ |                     'links' => [ | ||||||
|                         'mandate' => $token->token, |                         'mandate' => $request->source, | ||||||
|                     ], |                     ], | ||||||
|                 ], |                 ], | ||||||
|             ]); |             ]); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|             if ($payment->status === 'pending_submission') { |             if ($payment->status === 'pending_submission') { | ||||||
|                 return $this->processPendingPayment($payment, ['token' => $token->hashed_id]); |                 return $this->processPendingPayment($payment, ['token' => $request->source]); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             return $this->processUnsuccessfulPayment($payment); |             return $this->processUnsuccessfulPayment($payment); | ||||||
| @ -193,7 +190,6 @@ class DirectDebit implements MethodInterface | |||||||
|     public function processPendingPayment(\GoCardlessPro\Resources\Payment $payment, array $data = []) |     public function processPendingPayment(\GoCardlessPro\Resources\Payment $payment, array $data = []) | ||||||
|     { |     { | ||||||
|         $data = [ |         $data = [ | ||||||
|             'payment_method' => $data['token'], |  | ||||||
|             'payment_type' => PaymentType::DIRECT_DEBIT, |             'payment_type' => PaymentType::DIRECT_DEBIT, | ||||||
|             'amount' => $this->go_cardless->payment_hash->data->amount_with_fee, |             'amount' => $this->go_cardless->payment_hash->data->amount_with_fee, | ||||||
|             'transaction_reference' => $payment->id, |             'transaction_reference' => $payment->id, | ||||||
|  | |||||||
| @ -160,11 +160,7 @@ class SEPA implements MethodInterface | |||||||
|      */ |      */ | ||||||
|     public function paymentResponse(PaymentResponseRequest $request) |     public function paymentResponse(PaymentResponseRequest $request) | ||||||
|     { |     { | ||||||
|         $token = ClientGatewayToken::find( |         $this->go_cardless->ensureMandateIsReady($request->source); | ||||||
|             $this->decodePrimaryKey($request->source) |  | ||||||
|         )->firstOrFail(); |  | ||||||
| 
 |  | ||||||
|         $this->go_cardless->ensureMandateIsReady($token); |  | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|             $payment = $this->go_cardless->gateway->payments()->create([ |             $payment = $this->go_cardless->gateway->payments()->create([ | ||||||
| @ -175,13 +171,13 @@ class SEPA implements MethodInterface | |||||||
|                         'payment_hash' => $this->go_cardless->payment_hash->hash, |                         'payment_hash' => $this->go_cardless->payment_hash->hash, | ||||||
|                     ], |                     ], | ||||||
|                     'links' => [ |                     'links' => [ | ||||||
|                         'mandate' => $token->token, |                         'mandate' => $request->source, | ||||||
|                     ], |                     ], | ||||||
|                 ], |                 ], | ||||||
|             ]); |             ]); | ||||||
| 
 | 
 | ||||||
|             if ($payment->status === 'pending_submission') { |             if ($payment->status === 'pending_submission') { | ||||||
|                 return $this->processPendingPayment($payment, ['token' => $token->hashed_id]); |                 return $this->processPendingPayment($payment, ['token' => $request->source]); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             return $this->processUnsuccessfulPayment($payment); |             return $this->processUnsuccessfulPayment($payment); | ||||||
| @ -200,7 +196,6 @@ class SEPA implements MethodInterface | |||||||
|     public function processPendingPayment(\GoCardlessPro\Resources\Payment $payment, array $data = []) |     public function processPendingPayment(\GoCardlessPro\Resources\Payment $payment, array $data = []) | ||||||
|     { |     { | ||||||
|         $data = [ |         $data = [ | ||||||
|             'payment_method' => $data['token'], |  | ||||||
|             'payment_type' => PaymentType::SEPA, |             'payment_type' => PaymentType::SEPA, | ||||||
|             'amount' => $this->go_cardless->payment_hash->data->amount_with_fee, |             'amount' => $this->go_cardless->payment_hash->data->amount_with_fee, | ||||||
|             'transaction_reference' => $payment->id, |             'transaction_reference' => $payment->id, | ||||||
|  | |||||||
| @ -265,10 +265,11 @@ class GoCardlessPaymentDriver extends BaseDriver | |||||||
|         return response()->json([], 200); |         return response()->json([], 200); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function ensureMandateIsReady(ClientGatewayToken $cgt) |     public function ensureMandateIsReady($token) | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             $mandate = $this->gateway->mandates()->get($cgt->token); |             $this->init(); | ||||||
|  |             $mandate = $this->gateway->mandates()->get($token); | ||||||
| 
 | 
 | ||||||
|             if ($mandate->status !== 'active') { |             if ($mandate->status !== 'active') { | ||||||
|                 throw new \Exception(ctrans('texts.gocardless_mandate_not_ready')); |                 throw new \Exception(ctrans('texts.gocardless_mandate_not_ready')); | ||||||
|  | |||||||
| @ -86,7 +86,9 @@ class Bancontact implements MethodInterface | |||||||
|                 'webhookUrl' => $this->mollie->company_gateway->webhookUrl(), |                 'webhookUrl' => $this->mollie->company_gateway->webhookUrl(), | ||||||
|                 'metadata' => [ |                 'metadata' => [ | ||||||
|                     'client_id' => $this->mollie->client->hashed_id, |                     'client_id' => $this->mollie->client->hashed_id, | ||||||
|                     'hash' => $this->mollie->payment_hash->hash |                     'hash' => $this->mollie->payment_hash->hash, | ||||||
|  |                     'gateway_type_id' => GatewayType::BANCONTACT, | ||||||
|  |                     'payment_type_id' => PaymentType::BANCONTACT, | ||||||
|                 ], |                 ], | ||||||
|             ]); |             ]); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -89,7 +89,9 @@ class BankTransfer implements MethodInterface | |||||||
|                 'webhookUrl' => $this->mollie->company_gateway->webhookUrl(), |                 'webhookUrl' => $this->mollie->company_gateway->webhookUrl(), | ||||||
|                 'metadata' => [ |                 'metadata' => [ | ||||||
|                     'client_id' => $this->mollie->client->hashed_id, |                     'client_id' => $this->mollie->client->hashed_id, | ||||||
|                     'hash' => $this->mollie->payment_hash->hash |                     'hash' => $this->mollie->payment_hash->hash, | ||||||
|  |                     'gateway_type_id' => GatewayType::BANK_TRANSFER, | ||||||
|  |                     'payment_type_id' => PaymentType::MOLLIE_BANK_TRANSFER, | ||||||
|                 ], |                 ], | ||||||
|             ]); |             ]); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -114,7 +114,7 @@ class CreditCard | |||||||
|                     'name' => $this->mollie->client->name, |                     'name' => $this->mollie->client->name, | ||||||
|                     'email' => $this->mollie->client->present()->email(), |                     'email' => $this->mollie->client->present()->email(), | ||||||
|                     'metadata' => [ |                     'metadata' => [ | ||||||
|                         'id' => $this->mollie->client->hashed_id, |                         'id' => $this->mollie->client->hashed_id | ||||||
|                     ], |                     ], | ||||||
|                 ]); |                 ]); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -86,7 +86,9 @@ class IDEAL implements MethodInterface | |||||||
|                 'webhookUrl' => $this->mollie->company_gateway->webhookUrl(), |                 'webhookUrl' => $this->mollie->company_gateway->webhookUrl(), | ||||||
|                 'metadata' => [ |                 'metadata' => [ | ||||||
|                     'client_id' => $this->mollie->client->hashed_id, |                     'client_id' => $this->mollie->client->hashed_id, | ||||||
|                     'hash' => $this->mollie->payment_hash->hash |                     'hash' => $this->mollie->payment_hash->hash, | ||||||
|  |                     'gateway_type_id' => GatewayType::IDEAL, | ||||||
|  |                     'payment_type_id' => PaymentType::IDEAL, | ||||||
|                 ], |                 ], | ||||||
|             ]); |             ]); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -86,7 +86,9 @@ class KBC implements MethodInterface | |||||||
|                 'webhookUrl' => $this->mollie->company_gateway->webhookUrl(), |                 'webhookUrl' => $this->mollie->company_gateway->webhookUrl(), | ||||||
|                 'metadata' => [ |                 'metadata' => [ | ||||||
|                     'client_id' => $this->mollie->client->hashed_id, |                     'client_id' => $this->mollie->client->hashed_id, | ||||||
|                     'hash' => $this->mollie->payment_hash->hash |                     'hash' => $this->mollie->payment_hash->hash, | ||||||
|  |                     'gateway_type_id' => GatewayType::KBC, | ||||||
|  |                     'payment_type_id' => PaymentType::KBC, | ||||||
|                 ], |                 ], | ||||||
|             ]); |             ]); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -312,10 +312,31 @@ class MolliePaymentDriver extends BaseDriver | |||||||
|                 $client = $record->client; |                 $client = $record->client; | ||||||
|             } |             } | ||||||
|             else{ |             else{ | ||||||
|                 nlog("mollie webhook"); |  | ||||||
|                 nlog($payment); |  | ||||||
| 
 | 
 | ||||||
|                 $client = Client::withTrashed()->find($this->decodePrimaryKey($payment->metadata->client_id)); |                 $client = Client::withTrashed()->find($this->decodePrimaryKey($payment->metadata->client_id)); | ||||||
|  | 
 | ||||||
|  |                 // sometimes if the user is not returned to the site with a response from Mollie 
 | ||||||
|  |                 // we may not have a payment record - in these cases we need to re-construct the payment
 | ||||||
|  |                 // record from the meta data in the payment hash.
 | ||||||
|  | 
 | ||||||
|  |                 if($payment && property_exists($payment->metadata, 'payment_hash') && $payment->metadata->payment_hash){ | ||||||
|  |                      | ||||||
|  |                     /* Harvest Payment Hash*/ | ||||||
|  |                     $payment_hash = PaymentHash::where('hash', $payment->metadata->hash)->first(); | ||||||
|  |                      | ||||||
|  |                     $data = [ | ||||||
|  |                         'gateway_type_id' => $payment->metadata->gateway_type_id, | ||||||
|  |                         'amount' => $amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total, | ||||||
|  |                         'payment_type' => $payment->metadata->payment_type_id, | ||||||
|  |                         'transaction_reference' => $payment->id, | ||||||
|  |                     ]; | ||||||
|  |                      | ||||||
|  |                     $record = $this->createPayment( | ||||||
|  |                         $data, | ||||||
|  |                         $codes[$payment->status] | ||||||
|  |                     ); | ||||||
|  |                  | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             $message = [ |             $message = [ | ||||||
|  | |||||||
| @ -136,6 +136,7 @@ class SquarePaymentDriver extends BaseDriver | |||||||
|         $amount_money->setCurrency($this->client->currency()->code); |         $amount_money->setCurrency($this->client->currency()->code); | ||||||
| 
 | 
 | ||||||
|         $body = new \Square\Models\CreatePaymentRequest($cgt->token, \Illuminate\Support\Str::random(32), $amount_money); |         $body = new \Square\Models\CreatePaymentRequest($cgt->token, \Illuminate\Support\Str::random(32), $amount_money); | ||||||
|  |         $body->setCustomerId($cgt->gateway_customer_reference); | ||||||
| 
 | 
 | ||||||
|         /** @var ApiResponse */ |         /** @var ApiResponse */ | ||||||
|         $response = $this->square->getPaymentsApi()->createPayment($body); |         $response = $this->square->getPaymentsApi()->createPayment($body); | ||||||
|  | |||||||
| @ -56,7 +56,6 @@ class Charge | |||||||
|         if($cgt->gateway_type_id == GatewayType::BANK_TRANSFER) |         if($cgt->gateway_type_id == GatewayType::BANK_TRANSFER) | ||||||
|             return (new ACH($this->stripe))->tokenBilling($cgt, $payment_hash); |             return (new ACH($this->stripe))->tokenBilling($cgt, $payment_hash); | ||||||
| 
 | 
 | ||||||
|         nlog(" DB = ".$this->stripe->client->company->db); |  | ||||||
|         $amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total; |         $amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total; | ||||||
|         $invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first(); |         $invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first(); | ||||||
| 
 | 
 | ||||||
| @ -119,7 +118,6 @@ class Charge | |||||||
|                     $data['message'] = $e->getMessage(); |                     $data['message'] = $e->getMessage(); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|                  |  | ||||||
| 
 | 
 | ||||||
|             $this->stripe->processInternallyFailedPayment($this->stripe, $e); |             $this->stripe->processInternallyFailedPayment($this->stripe, $e); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -123,7 +123,7 @@ class CreditCard | |||||||
| 
 | 
 | ||||||
|         $data = [ |         $data = [ | ||||||
|             'payment_method' => $this->stripe->payment_hash->data->server_response->payment_method, |             'payment_method' => $this->stripe->payment_hash->data->server_response->payment_method, | ||||||
|             'payment_type' => PaymentType::parseCardType(strtolower($stripe_method->card->brand)), |             'payment_type' => PaymentType::parseCardType(strtolower($stripe_method->card->brand)) ?: PaymentType::CREDIT_CARD_OTHER, | ||||||
|             'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->server_response->amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency()), |             'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->server_response->amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency()), | ||||||
|             'transaction_reference' => optional($this->stripe->payment_hash->data->payment_intent->charges->data[0])->id, |             'transaction_reference' => optional($this->stripe->payment_hash->data->payment_intent->charges->data[0])->id, | ||||||
|             'gateway_type_id' => GatewayType::CREDIT_CARD, |             'gateway_type_id' => GatewayType::CREDIT_CARD, | ||||||
|  | |||||||
| @ -436,7 +436,7 @@ class StripePaymentDriver extends BaseDriver | |||||||
| 
 | 
 | ||||||
|         //Else create a new record
 |         //Else create a new record
 | ||||||
|         $data['name'] = $this->client->present()->name(); |         $data['name'] = $this->client->present()->name(); | ||||||
|         $data['phone'] = $this->client->present()->phone(); |         $data['phone'] = substr($this->client->present()->phone(), 0 , 20); | ||||||
| 
 | 
 | ||||||
|         if (filter_var($this->client->present()->email(), FILTER_VALIDATE_EMAIL)) { |         if (filter_var($this->client->present()->email(), FILTER_VALIDATE_EMAIL)) { | ||||||
|             $data['email'] = $this->client->present()->email(); |             $data['email'] = $this->client->present()->email(); | ||||||
|  | |||||||
| @ -54,6 +54,37 @@ class TaskRepository extends BaseRepository | |||||||
|             $task->status_order = $data['status_order']; |             $task->status_order = $data['status_order']; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /*V4 override*/ | ||||||
|  |         if (! empty($data['time_details'])) { | ||||||
|  |             $timeLog = []; | ||||||
|  |             foreach ($data['time_details'] as $detail) { | ||||||
|  |                 $startTime = strtotime($detail['start_datetime']); | ||||||
|  |                 $endTime = false; | ||||||
|  |                 if (! empty($detail['end_datetime'])) { | ||||||
|  |                     $endTime = strtotime($detail['end_datetime']); | ||||||
|  |                 } else { | ||||||
|  |                     $duration = 0; | ||||||
|  |                     if (! empty($detail['duration_seconds'])) { | ||||||
|  |                         $duration += $detail['duration_seconds']; | ||||||
|  |                     } | ||||||
|  |                     if (! empty($detail['duration_minutes'])) { | ||||||
|  |                         $duration += $detail['duration_minutes'] * 60; | ||||||
|  |                     } | ||||||
|  |                     if (! empty($detail['duration_hours'])) { | ||||||
|  |                         $duration += $detail['duration_hours'] * 60 * 60; | ||||||
|  |                     } | ||||||
|  |                     if ($duration) { | ||||||
|  |                         $endTime = $startTime + $duration; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 $timeLog[] = [$startTime, $endTime]; | ||||||
|  |                 if (! $endTime) { | ||||||
|  |                     $data['is_running'] = true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             $data['time_log'] = json_encode($timeLog); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if (isset($data['time_log'])) { |         if (isset($data['time_log'])) { | ||||||
|             $time_log = json_decode($data['time_log']); |             $time_log = json_decode($data['time_log']); | ||||||
|         } elseif ($task->time_log) { |         } elseif ($task->time_log) { | ||||||
|  | |||||||
| @ -30,6 +30,7 @@ use App\Utils\PhantomJS\Phantom; | |||||||
| use App\Utils\Traits\Pdf\PdfMaker as PdfMakerTrait; | use App\Utils\Traits\Pdf\PdfMaker as PdfMakerTrait; | ||||||
| use Illuminate\Database\Eloquent\Collection; | use Illuminate\Database\Eloquent\Collection; | ||||||
| use Illuminate\Support\Facades\DB; | use Illuminate\Support\Facades\DB; | ||||||
|  | use Illuminate\Support\LazyCollection; | ||||||
| 
 | 
 | ||||||
| class Statement | class Statement | ||||||
| { | { | ||||||
| @ -217,7 +218,7 @@ class Statement | |||||||
|      * |      * | ||||||
|      * @return Invoice[]|\Illuminate\Database\Eloquent\Collection |      * @return Invoice[]|\Illuminate\Database\Eloquent\Collection | ||||||
|      */ |      */ | ||||||
|     protected function getInvoices(): Collection |     protected function getInvoices(): LazyCollection | ||||||
|     { |     { | ||||||
|         return Invoice::withTrashed() |         return Invoice::withTrashed() | ||||||
|             ->where('is_deleted', false) |             ->where('is_deleted', false) | ||||||
| @ -226,7 +227,7 @@ class Statement | |||||||
|             ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID]) |             ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID]) | ||||||
|             ->whereBetween('date', [$this->options['start_date'], $this->options['end_date']]) |             ->whereBetween('date', [$this->options['start_date'], $this->options['end_date']]) | ||||||
|             ->orderBy('number', 'ASC') |             ->orderBy('number', 'ASC') | ||||||
|             ->get(); |             ->cursor(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -234,7 +235,7 @@ class Statement | |||||||
|      * |      * | ||||||
|      * @return Payment[]|\Illuminate\Database\Eloquent\Collection |      * @return Payment[]|\Illuminate\Database\Eloquent\Collection | ||||||
|      */ |      */ | ||||||
|     protected function getPayments(): Collection |     protected function getPayments(): LazyCollection | ||||||
|     { |     { | ||||||
|         return Payment::withTrashed() |         return Payment::withTrashed() | ||||||
|             ->with('client.country','invoices') |             ->with('client.country','invoices') | ||||||
| @ -244,7 +245,7 @@ class Statement | |||||||
|             ->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED]) |             ->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED]) | ||||||
|             ->whereBetween('date', [$this->options['start_date'], $this->options['end_date']]) |             ->whereBetween('date', [$this->options['start_date'], $this->options['end_date']]) | ||||||
|             ->orderBy('number', 'ASC') |             ->orderBy('number', 'ASC') | ||||||
|             ->get(); |             ->cursor(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -36,17 +36,6 @@ class TriggeredActions extends AbstractService | |||||||
| 
 | 
 | ||||||
|     public function run() |     public function run() | ||||||
|     { |     { | ||||||
|         // if ($this->request->has('auto_bill') && $this->request->input('auto_bill') == 'true') {
 |  | ||||||
|         //     $this->credit = $this->credit->service()->autoBill()->save();
 |  | ||||||
|         // }
 |  | ||||||
| 
 |  | ||||||
|         // if ($this->request->has('paid') && $this->request->input('paid') == 'true') {
 |  | ||||||
|         //     $this->credit = $this->credit->service()->markPaid()->save();
 |  | ||||||
|         // }
 |  | ||||||
| 
 |  | ||||||
|         // if ($this->request->has('amount_paid') && is_numeric($this->request->input('amount_paid')) ) {
 |  | ||||||
|         //     $this->credit = $this->credit->service()->applyPaymentAmount($this->request->input('amount_paid'))->save();
 |  | ||||||
|         // }
 |  | ||||||
| 
 | 
 | ||||||
|         if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') { |         if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') { | ||||||
|             $this->sendEmail(); |             $this->sendEmail(); | ||||||
|  | |||||||
| @ -105,7 +105,7 @@ class AddGatewayFee extends AbstractService | |||||||
|         $invoice_item->quantity = 1; |         $invoice_item->quantity = 1; | ||||||
|         $invoice_item->cost = $gateway_fee; |         $invoice_item->cost = $gateway_fee; | ||||||
| 
 | 
 | ||||||
|         if ($fees_and_limits = $this->company_gateway->getFeesAndLimits()) { |         if ($fees_and_limits = $this->company_gateway->getFeesAndLimits($this->gateway_type_id)) { | ||||||
|             $invoice_item->tax_rate1 = $fees_and_limits->fee_tax_rate1; |             $invoice_item->tax_rate1 = $fees_and_limits->fee_tax_rate1; | ||||||
|             $invoice_item->tax_rate2 = $fees_and_limits->fee_tax_rate2; |             $invoice_item->tax_rate2 = $fees_and_limits->fee_tax_rate2; | ||||||
|             $invoice_item->tax_rate3 = $fees_and_limits->fee_tax_rate3; |             $invoice_item->tax_rate3 = $fees_and_limits->fee_tax_rate3; | ||||||
|  | |||||||
| @ -130,7 +130,7 @@ class AutoBillInvoice extends AbstractService | |||||||
|             info("Auto Bill payment captured for ".$this->invoice->number); |             info("Auto Bill payment captured for ".$this->invoice->number); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return $this->invoice->fresh(); |         // return $this->invoice->fresh();
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -138,7 +138,8 @@ class InvoiceService | |||||||
|     { |     { | ||||||
|         // $this->invoice = (new UpdateBalance($this->invoice, $balance_adjustment, $is_draft))->run();
 |         // $this->invoice = (new UpdateBalance($this->invoice, $balance_adjustment, $is_draft))->run();
 | ||||||
| 
 | 
 | ||||||
|         if ($this->invoice->is_deleted) { |         if ((bool)$this->invoice->is_deleted !== false) { | ||||||
|  |             nlog($this->invoice->number . " is deleted returning"); | ||||||
|             return $this; |             return $this; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -245,7 +246,7 @@ class InvoiceService | |||||||
| 
 | 
 | ||||||
|     public function autoBill() |     public function autoBill() | ||||||
|     { |     { | ||||||
|         $this->invoice = (new AutoBillInvoice($this->invoice, $this->invoice->company->db))->run(); |         (new AutoBillInvoice($this->invoice, $this->invoice->company->db))->run(); | ||||||
| 
 | 
 | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
| @ -483,6 +484,10 @@ class InvoiceService | |||||||
|         if(!isset($this->invoice->exchange_rate) && $this->invoice->client->currency()->id != (int) $this->invoice->company->settings->currency_id) |         if(!isset($this->invoice->exchange_rate) && $this->invoice->client->currency()->id != (int) $this->invoice->company->settings->currency_id) | ||||||
|             $this->invoice->exchange_rate = $this->invoice->client->currency()->exchange_rate; |             $this->invoice->exchange_rate = $this->invoice->client->currency()->exchange_rate; | ||||||
| 
 | 
 | ||||||
|  |         if($settings->counter_number_applied == 'when_saved'){ | ||||||
|  |             $this->invoice->service()->applyNumber()->save(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -37,7 +37,7 @@ class TriggeredActions extends AbstractService | |||||||
|     public function run() |     public function run() | ||||||
|     { |     { | ||||||
|         if ($this->request->has('auto_bill') && $this->request->input('auto_bill') == 'true') { |         if ($this->request->has('auto_bill') && $this->request->input('auto_bill') == 'true') { | ||||||
|             $this->invoice = $this->invoice->service()->autoBill()->save(); |             $this->invoice->service()->autoBill(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if ($this->request->has('paid') && $this->request->input('paid') == 'true') { |         if ($this->request->has('paid') && $this->request->input('paid') == 'true') { | ||||||
|  | |||||||
| @ -124,10 +124,10 @@ class QuoteService | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         if ($this->quote->client->getSetting('auto_archive_quote')) { |         // if ($this->quote->client->getSetting('auto_archive_quote')) {
 | ||||||
|             $quote_repo = new QuoteRepository(); |         //     $quote_repo = new QuoteRepository();
 | ||||||
|             $quote_repo->archive($this->quote); |         //     $quote_repo->archive($this->quote);
 | ||||||
|         } |         // }
 | ||||||
| 
 | 
 | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -57,7 +57,7 @@ class TriggeredActions extends AbstractService | |||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
|         $reminder_template = $this->quote->calculateTemplate('quote'); |         $reminder_template = $this->quote->calculateTemplate('quote'); | ||||||
|         //$reminder_template = 'payment';
 |         // $reminder_template = 'email_template_quote';
 | ||||||
| 
 | 
 | ||||||
|         $this->quote->invitations->load('contact.client.country', 'quote.client.country', 'quote.company')->each(function ($invitation) use ($reminder_template) { |         $this->quote->invitations->load('contact.client.country', 'quote.client.country', 'quote.company')->each(function ($invitation) use ($reminder_template) { | ||||||
|             EmailEntity::dispatch($invitation, $this->quote->company, $reminder_template); |             EmailEntity::dispatch($invitation, $this->quote->company, $reminder_template); | ||||||
|  | |||||||
| @ -77,8 +77,6 @@ class SubscriptionService | |||||||
|             $recurring_invoice_repo = new RecurringInvoiceRepository(); |             $recurring_invoice_repo = new RecurringInvoiceRepository(); | ||||||
| 
 | 
 | ||||||
|             $recurring_invoice = $recurring_invoice_repo->save([], $recurring_invoice); |             $recurring_invoice = $recurring_invoice_repo->save([], $recurring_invoice); | ||||||
|             // $recurring_invoice->next_send_date = now()->format('Y-m-d');
 |  | ||||||
|             // $recurring_invoice->next_send_date = $recurring_invoice->nextSendDate();
 |  | ||||||
|             $recurring_invoice->auto_bill = $this->subscription->auto_bill; |             $recurring_invoice->auto_bill = $this->subscription->auto_bill; | ||||||
|              |              | ||||||
|             /* Start the recurring service */ |             /* Start the recurring service */ | ||||||
| @ -87,7 +85,6 @@ class SubscriptionService | |||||||
|                               ->save(); |                               ->save(); | ||||||
| 
 | 
 | ||||||
|             //execute any webhooks
 |             //execute any webhooks
 | ||||||
| 
 |  | ||||||
|             $context = [ |             $context = [ | ||||||
|                 'context' => 'recurring_purchase', |                 'context' => 'recurring_purchase', | ||||||
|                 'recurring_invoice' => $recurring_invoice->hashed_id, |                 'recurring_invoice' => $recurring_invoice->hashed_id, | ||||||
| @ -95,6 +92,7 @@ class SubscriptionService | |||||||
|                 'client' => $recurring_invoice->client->hashed_id, |                 'client' => $recurring_invoice->client->hashed_id, | ||||||
|                 'subscription' => $this->subscription->hashed_id, |                 'subscription' => $this->subscription->hashed_id, | ||||||
|                 'contact' => auth('contact')->user()->hashed_id, |                 'contact' => auth('contact')->user()->hashed_id, | ||||||
|  |                 'account_key' => $recurring_invoice->client->custom_value2, | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             $response = $this->triggerWebhook($context); |             $response = $this->triggerWebhook($context); | ||||||
| @ -111,6 +109,7 @@ class SubscriptionService | |||||||
|                 'invoice' => $this->encodePrimaryKey($payment_hash->fee_invoice_id), |                 'invoice' => $this->encodePrimaryKey($payment_hash->fee_invoice_id), | ||||||
|                 'client'  => $invoice->client->hashed_id, |                 'client'  => $invoice->client->hashed_id, | ||||||
|                 'subscription' => $this->subscription->hashed_id, |                 'subscription' => $this->subscription->hashed_id, | ||||||
|  |                 'account_key' => $invoice->client->custom_value2, | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             //execute any webhooks
 |             //execute any webhooks
 | ||||||
| @ -130,6 +129,7 @@ class SubscriptionService | |||||||
|             'contact' => $contact->hashed_id, |             'contact' => $contact->hashed_id, | ||||||
|             'contact_email' => $contact->email, |             'contact_email' => $contact->email, | ||||||
|             'client' => $contact->client->hashed_id, |             'client' => $contact->client->hashed_id, | ||||||
|  |             'account_key' => $contact->client->custom_value2, | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|         $response = $this->triggerWebhook($context); |         $response = $this->triggerWebhook($context); | ||||||
| @ -180,6 +180,7 @@ class SubscriptionService | |||||||
|                 'recurring_invoice' => $recurring_invoice->hashed_id, |                 'recurring_invoice' => $recurring_invoice->hashed_id, | ||||||
|                 'client' => $recurring_invoice->client->hashed_id, |                 'client' => $recurring_invoice->client->hashed_id, | ||||||
|                 'subscription' => $this->subscription->hashed_id, |                 'subscription' => $this->subscription->hashed_id, | ||||||
|  |                 'account_key' => $recurring_invoice->client->custom_value2, | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|         //execute any webhooks
 |         //execute any webhooks
 | ||||||
| @ -452,6 +453,7 @@ class SubscriptionService | |||||||
|                 'client' => $new_recurring_invoice->client->hashed_id, |                 'client' => $new_recurring_invoice->client->hashed_id, | ||||||
|                 'subscription' => $target_subscription->hashed_id, |                 'subscription' => $target_subscription->hashed_id, | ||||||
|                 'contact' => auth('contact')->user()->hashed_id, |                 'contact' => auth('contact')->user()->hashed_id, | ||||||
|  |                 'account_key' => $new_recurring_invoice->client->custom_value2, | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             $response = $this->triggerWebhook($context); |             $response = $this->triggerWebhook($context); | ||||||
| @ -572,6 +574,7 @@ class SubscriptionService | |||||||
|             'client' => $recurring_invoice->client->hashed_id, |             'client' => $recurring_invoice->client->hashed_id, | ||||||
|             'subscription' => $this->subscription->hashed_id, |             'subscription' => $this->subscription->hashed_id, | ||||||
|             'contact' => auth('contact')->user()->hashed_id, |             'contact' => auth('contact')->user()->hashed_id, | ||||||
|  |             'account_key' => $recurring_invoice->client->custom_value2, | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -768,8 +771,6 @@ class SubscriptionService | |||||||
|         $response = false; |         $response = false; | ||||||
| 
 | 
 | ||||||
|         $body = array_merge($context, [ |         $body = array_merge($context, [ | ||||||
|             'company_key' => $this->subscription->company->company_key, |  | ||||||
|             'account_key' => $this->subscription->company->account->key, |  | ||||||
|             'db' => $this->subscription->company->db, |             'db' => $this->subscription->company->db, | ||||||
|         ]); |         ]); | ||||||
| 
 | 
 | ||||||
| @ -921,6 +922,7 @@ class SubscriptionService | |||||||
|                 'recurring_invoice' => $recurring_invoice->hashed_id, |                 'recurring_invoice' => $recurring_invoice->hashed_id, | ||||||
|                 'client' => $recurring_invoice->client->hashed_id, |                 'client' => $recurring_invoice->client->hashed_id, | ||||||
|                 'contact' => auth('contact')->user()->hashed_id, |                 'contact' => auth('contact')->user()->hashed_id, | ||||||
|  |                 'account_key' => $recurring_invoice->client->custom_value2, | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|             $this->triggerWebhook($context); |             $this->triggerWebhook($context); | ||||||
| @ -1043,6 +1045,7 @@ class SubscriptionService | |||||||
|                 'client' => $invoice->client->hashed_id, |                 'client' => $invoice->client->hashed_id, | ||||||
|                 'contact' => $invoice->client->primary_contact()->first() ? $invoice->client->primary_contact()->first()->hashed_id: $invoice->client->contacts->first()->hashed_id, |                 'contact' => $invoice->client->primary_contact()->first() ? $invoice->client->primary_contact()->first()->hashed_id: $invoice->client->contacts->first()->hashed_id, | ||||||
|                 'invoice' => $invoice->hashed_id, |                 'invoice' => $invoice->hashed_id, | ||||||
|  |                 'account_key' => $invoice->client->custom_value2, | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|         $response = $this->triggerWebhook($context); |         $response = $this->triggerWebhook($context); | ||||||
|  | |||||||
| @ -11,6 +11,12 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Utils\Traits\Notifications; | namespace App\Utils\Traits\Notifications; | ||||||
| 
 | 
 | ||||||
|  | use App\Models\Client; | ||||||
|  | use App\Models\Credit; | ||||||
|  | use App\Models\Invoice; | ||||||
|  | use App\Models\Payment; | ||||||
|  | use App\Models\Quote; | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * Class UserNotifies. |  * Class UserNotifies. | ||||||
|  * |  * | ||||||
| @ -22,53 +28,100 @@ trait UserNotifies | |||||||
| { | { | ||||||
|     public function findUserNotificationTypes($invitation, $company_user, $entity_name, $required_permissions) :array |     public function findUserNotificationTypes($invitation, $company_user, $entity_name, $required_permissions) :array | ||||||
|     { |     { | ||||||
|         if ($company_user->company->is_disabled) { |  | ||||||
|             return []; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         $notifiable_methods = []; |         $notifiable_methods = []; | ||||||
|         $notifications = $company_user->notifications; |         $notifications = $company_user->notifications; | ||||||
| 
 | 
 | ||||||
|  |         if ($company_user->company->is_disabled && is_array($notifications->email)) { | ||||||
|  |             return []; | ||||||
|  |         } | ||||||
|  |          | ||||||
|         //if a user owns this record or is assigned to it, they are attached the permission for notification.
 |         //if a user owns this record or is assigned to it, they are attached the permission for notification.
 | ||||||
|         if ($invitation->{$entity_name}->user_id == $company_user->_user_id || $invitation->{$entity_name}->assigned_user_id == $company_user->user_id) { |         if ($invitation->{$entity_name}->user_id == $company_user->_user_id || $invitation->{$entity_name}->assigned_user_id == $company_user->user_id) { | ||||||
|             array_push($required_permissions, 'all_user_notifications'); |             $required_permissions = $this->addSpecialUserPermissionForEntity($invitation->{$entity_name}, $required_permissions); | ||||||
|  |         } | ||||||
|  |         else{ | ||||||
|  |             $required_permissions = $this->removeSpecialUserPermissionForEntity($invitation->{$entity_name}, $required_permissions); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect(['all_user_notifications'], $notifications->email)) >= 1 || count(array_intersect(['all_notifications'],$notifications->email)) >= 1) { |         if (count(array_intersect($required_permissions, $notifications->email)) >= 1) { | ||||||
|             array_push($notifiable_methods, 'mail'); |             array_push($notifiable_methods, 'mail'); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // if(count(array_intersect($required_permissions, $notifications->slack)) >=1)
 |  | ||||||
|         //     array_push($notifiable_methods, 'slack');
 |  | ||||||
| 
 |  | ||||||
|         return $notifiable_methods; |         return $notifiable_methods; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function findUserEntityNotificationType($entity, $company_user, $required_permissions) :array |     public function findUserEntityNotificationType($entity, $company_user, array $required_permissions) :array | ||||||
|     { |     { | ||||||
|         if ($company_user->company->is_disabled) { |  | ||||||
|             return []; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $notifiable_methods = []; |         $notifiable_methods = []; | ||||||
|         $notifications = $company_user->notifications; |         $notifications = $company_user->notifications; | ||||||
| 
 | 
 | ||||||
|         if (! $notifications) { |         if ($company_user->company->is_disabled || ! $notifications) { | ||||||
|             return []; |             return []; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if ($entity->user_id == $company_user->_user_id || $entity->assigned_user_id == $company_user->user_id) { |         if ($entity->user_id == $company_user->_user_id || $entity->assigned_user_id == $company_user->user_id) { | ||||||
|             array_push($required_permissions, 'all_user_notifications'); |             $required_permissions = $this->addSpecialUserPermissionForEntity($entity, $required_permissions); | ||||||
|  |         } | ||||||
|  |         else{ | ||||||
|  |             $required_permissions = $this->removeSpecialUserPermissionForEntity($entity, $required_permissions); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect(['all_user_notifications'], $notifications->email)) >= 1 || count(array_intersect(['all_notifications'],$notifications->email)) >= 1) { |         if (count(array_intersect($required_permissions, $notifications->email)) >= 1) { | ||||||
|             array_push($notifiable_methods, 'mail'); |             array_push($notifiable_methods, 'mail'); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         return $notifiable_methods; |         return $notifiable_methods; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private function addSpecialUserPermissionForEntity($entity, array $required_permissions) :array | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         array_merge($required_permissions, ["all_notifications"]); | ||||||
|  | 
 | ||||||
|  |         switch ($entity) { | ||||||
|  |             case ($entity instanceof Payment || $entity instanceof Client): //we pass client also as this is the proxy for Payment Failures (ie, there is no payment)
 | ||||||
|  |                 return array_merge($required_permissions, ["all_notifications","all_user_notifications","payment_failure_user","payment_success_user"]); | ||||||
|  |                 break; | ||||||
|  |             case ($entity instanceof Invoice): | ||||||
|  |                 return array_merge($required_permissions, ["all_notifications","all_user_notifications","invoice_created_user","invoice_sent_user","invoice_viewed_user","invoice_late_user"]); | ||||||
|  |                 break; | ||||||
|  |             case ($entity instanceof Quote): | ||||||
|  |                 return array_merge($required_permissions, ["all_notifications","all_user_notifications","quote_created_user","quote_sent_user","quote_viewed_user","quote_approved_user","quote_expired_user"]); | ||||||
|  |                 break; | ||||||
|  |             case ($entity instanceof Credit): | ||||||
|  |                 return array_merge($required_permissions, ["all_notifications","all_user_notifications","credit_created_user","credit_sent_user","credit_viewed_user"]); | ||||||
|  |                 break;             | ||||||
|  |             default: | ||||||
|  |                 return []; | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function removeSpecialUserPermissionForEntity($entity, $required_permissions) | ||||||
|  |     { | ||||||
|  |         array_merge($required_permissions, ["all_notifications"]); | ||||||
|  | 
 | ||||||
|  |         switch ($entity) { | ||||||
|  |             case ($entity instanceof Payment || $entity instanceof Client): //we pass client also as this is the proxy for Payment Failures (ie, there is no payment)
 | ||||||
|  |                 return array_diff($required_permissions, ["all_user_notifications","payment_failure_user","payment_success_user"]); | ||||||
|  |                 break; | ||||||
|  |             case ($entity instanceof Invoice): | ||||||
|  |                 return array_diff($required_permissions, ["all_user_notifications","invoice_created_user","invoice_sent_user","invoice_viewed_user","invoice_late_user"]); | ||||||
|  |                 break; | ||||||
|  |             case ($entity instanceof Quote): | ||||||
|  |                 return array_diff($required_permissions, ["all_user_notifications","quote_created_user","quote_sent_user","quote_viewed_user","quote_approved_user","quote_expired_user"]); | ||||||
|  |                 break; | ||||||
|  |             case ($entity instanceof Credit): | ||||||
|  |                 return array_diff($required_permissions, ["all_user_notifications","credit_created_user","credit_sent_user","credit_viewed_user"]); | ||||||
|  |                 break;             | ||||||
|  |             default: | ||||||
|  |                 // code...
 | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     public function findCompanyUserNotificationType($company_user, $required_permissions) :array |     public function findCompanyUserNotificationType($company_user, $required_permissions) :array | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -26,7 +26,7 @@ | |||||||
|     ], |     ], | ||||||
|     "type": "project", |     "type": "project", | ||||||
|     "require": { |     "require": { | ||||||
|         "php": "^7.4|^8.0", |         "php": "^7.4|^8", | ||||||
|         "ext-dom": "*", |         "ext-dom": "*", | ||||||
|         "ext-json": "*", |         "ext-json": "*", | ||||||
|         "ext-libxml": "*", |         "ext-libxml": "*", | ||||||
|  | |||||||
							
								
								
									
										715
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										715
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -14,8 +14,8 @@ return [ | |||||||
|     'require_https' => env('REQUIRE_HTTPS', true), |     'require_https' => env('REQUIRE_HTTPS', true), | ||||||
|     'app_url' => rtrim(env('APP_URL', ''), '/'), |     'app_url' => rtrim(env('APP_URL', ''), '/'), | ||||||
|     'app_domain' => env('APP_DOMAIN', 'invoicing.co'), |     'app_domain' => env('APP_DOMAIN', 'invoicing.co'), | ||||||
|     'app_version' => '5.3.33', |     'app_version' => '5.3.34', | ||||||
|     'app_tag' => '5.3.33', |     'app_tag' => '5.3.34', | ||||||
|     'minimum_client_version' => '5.0.16', |     'minimum_client_version' => '5.0.16', | ||||||
|     'terms_version' => '1.0.1', |     'terms_version' => '1.0.1', | ||||||
|     'api_secret' => env('API_SECRET', ''), |     'api_secret' => env('API_SECRET', ''), | ||||||
|  | |||||||
| @ -34,6 +34,9 @@ CREATE TABLE `accounts` ( | |||||||
|   `updated_at` timestamp(6) NULL DEFAULT NULL, |   `updated_at` timestamp(6) NULL DEFAULT NULL, | ||||||
|   `is_scheduler_running` tinyint(1) NOT NULL DEFAULT '0', |   `is_scheduler_running` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|   `trial_duration` int(10) unsigned DEFAULT NULL, |   `trial_duration` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `is_onboarding` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|  |   `onboarding` mediumtext COLLATE utf8mb4_unicode_ci, | ||||||
|  |   `is_migrated` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|   PRIMARY KEY (`id`), |   PRIMARY KEY (`id`), | ||||||
|   KEY `accounts_payment_id_index` (`payment_id`) |   KEY `accounts_payment_id_index` (`payment_id`) | ||||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; | ||||||
| @ -66,6 +69,8 @@ CREATE TABLE `activities` ( | |||||||
|   `quote_id` int(10) unsigned DEFAULT NULL, |   `quote_id` int(10) unsigned DEFAULT NULL, | ||||||
|   `subscription_id` int(10) unsigned DEFAULT NULL, |   `subscription_id` int(10) unsigned DEFAULT NULL, | ||||||
|   `recurring_invoice_id` int(10) unsigned DEFAULT NULL, |   `recurring_invoice_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `recurring_expense_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `recurring_quote_id` int(10) unsigned DEFAULT NULL, | ||||||
|   PRIMARY KEY (`id`), |   PRIMARY KEY (`id`), | ||||||
|   KEY `activities_vendor_id_company_id_index` (`vendor_id`,`company_id`), |   KEY `activities_vendor_id_company_id_index` (`vendor_id`,`company_id`), | ||||||
|   KEY `activities_project_id_company_id_index` (`project_id`,`company_id`), |   KEY `activities_project_id_company_id_index` (`project_id`,`company_id`), | ||||||
| @ -93,6 +98,7 @@ CREATE TABLE `backups` ( | |||||||
|   `created_at` timestamp(6) NULL DEFAULT NULL, |   `created_at` timestamp(6) NULL DEFAULT NULL, | ||||||
|   `updated_at` timestamp(6) NULL DEFAULT NULL, |   `updated_at` timestamp(6) NULL DEFAULT NULL, | ||||||
|   `amount` decimal(16,4) NOT NULL, |   `amount` decimal(16,4) NOT NULL, | ||||||
|  |   `filename` text COLLATE utf8mb4_unicode_ci, | ||||||
|   PRIMARY KEY (`id`), |   PRIMARY KEY (`id`), | ||||||
|   KEY `backups_activity_id_foreign` (`activity_id`), |   KEY `backups_activity_id_foreign` (`activity_id`), | ||||||
|   CONSTRAINT `backups_activity_id_foreign` FOREIGN KEY (`activity_id`) REFERENCES `activities` (`id`) ON DELETE CASCADE ON UPDATE CASCADE |   CONSTRAINT `backups_activity_id_foreign` FOREIGN KEY (`activity_id`) REFERENCES `activities` (`id`) ON DELETE CASCADE ON UPDATE CASCADE | ||||||
| @ -378,6 +384,7 @@ CREATE TABLE `companies` ( | |||||||
|   `markdown_enabled` tinyint(1) NOT NULL DEFAULT '1', |   `markdown_enabled` tinyint(1) NOT NULL DEFAULT '1', | ||||||
|   `use_comma_as_decimal_place` tinyint(1) NOT NULL DEFAULT '0', |   `use_comma_as_decimal_place` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|   `report_include_drafts` tinyint(1) NOT NULL DEFAULT '0', |   `report_include_drafts` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|  |   `client_registration_fields` mediumtext COLLATE utf8mb4_unicode_ci, | ||||||
|   PRIMARY KEY (`id`), |   PRIMARY KEY (`id`), | ||||||
|   UNIQUE KEY `companies_company_key_unique` (`company_key`), |   UNIQUE KEY `companies_company_key_unique` (`company_key`), | ||||||
|   KEY `companies_industry_id_foreign` (`industry_id`), |   KEY `companies_industry_id_foreign` (`industry_id`), | ||||||
| @ -1371,6 +1378,69 @@ CREATE TABLE `quotes` ( | |||||||
|   CONSTRAINT `quotes_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE |   CONSTRAINT `quotes_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE | ||||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; | ||||||
| /*!40101 SET character_set_client = @saved_cs_client */; | /*!40101 SET character_set_client = @saved_cs_client */; | ||||||
|  | DROP TABLE IF EXISTS `recurring_expenses`; | ||||||
|  | /*!40101 SET @saved_cs_client     = @@character_set_client */; | ||||||
|  | /*!40101 SET character_set_client = utf8 */; | ||||||
|  | CREATE TABLE `recurring_expenses` ( | ||||||
|  |   `id` int(10) unsigned NOT NULL AUTO_INCREMENT, | ||||||
|  |   `created_at` timestamp(6) NULL DEFAULT NULL, | ||||||
|  |   `updated_at` timestamp(6) NULL DEFAULT NULL, | ||||||
|  |   `deleted_at` timestamp NULL DEFAULT NULL, | ||||||
|  |   `company_id` int(10) unsigned NOT NULL, | ||||||
|  |   `vendor_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `user_id` int(10) unsigned NOT NULL, | ||||||
|  |   `status_id` int(10) unsigned NOT NULL, | ||||||
|  |   `invoice_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `client_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `bank_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `project_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `payment_type_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `recurring_expense_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `is_deleted` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|  |   `uses_inclusive_taxes` tinyint(1) NOT NULL DEFAULT '1', | ||||||
|  |   `tax_name1` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, | ||||||
|  |   `tax_name2` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, | ||||||
|  |   `tax_name3` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, | ||||||
|  |   `date` date DEFAULT NULL, | ||||||
|  |   `payment_date` date DEFAULT NULL, | ||||||
|  |   `should_be_invoiced` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|  |   `invoice_documents` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|  |   `transaction_id` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, | ||||||
|  |   `custom_value1` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, | ||||||
|  |   `custom_value2` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, | ||||||
|  |   `custom_value3` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, | ||||||
|  |   `custom_value4` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, | ||||||
|  |   `category_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `calculate_tax_by_amount` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|  |   `tax_amount1` decimal(20,6) DEFAULT NULL, | ||||||
|  |   `tax_amount2` decimal(20,6) DEFAULT NULL, | ||||||
|  |   `tax_amount3` decimal(20,6) DEFAULT NULL, | ||||||
|  |   `tax_rate1` decimal(20,6) DEFAULT NULL, | ||||||
|  |   `tax_rate2` decimal(20,6) DEFAULT NULL, | ||||||
|  |   `tax_rate3` decimal(20,6) DEFAULT NULL, | ||||||
|  |   `amount` decimal(20,6) DEFAULT NULL, | ||||||
|  |   `foreign_amount` decimal(20,6) DEFAULT NULL, | ||||||
|  |   `exchange_rate` decimal(20,6) NOT NULL DEFAULT '1.000000', | ||||||
|  |   `assigned_user_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `number` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, | ||||||
|  |   `invoice_currency_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `currency_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `private_notes` text COLLATE utf8mb4_unicode_ci, | ||||||
|  |   `public_notes` text COLLATE utf8mb4_unicode_ci, | ||||||
|  |   `transaction_reference` text COLLATE utf8mb4_unicode_ci, | ||||||
|  |   `frequency_id` int(10) unsigned NOT NULL, | ||||||
|  |   `last_sent_date` datetime DEFAULT NULL, | ||||||
|  |   `next_send_date` datetime DEFAULT NULL, | ||||||
|  |   `remaining_cycles` int(11) DEFAULT NULL, | ||||||
|  |   PRIMARY KEY (`id`), | ||||||
|  |   UNIQUE KEY `recurring_expenses_company_id_number_unique` (`company_id`,`number`), | ||||||
|  |   KEY `recurring_expenses_company_id_deleted_at_index` (`company_id`,`deleted_at`), | ||||||
|  |   KEY `recurring_expenses_user_id_foreign` (`user_id`), | ||||||
|  |   KEY `recurring_expenses_company_id_index` (`company_id`), | ||||||
|  |   CONSTRAINT `recurring_expenses_company_id_foreign` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, | ||||||
|  |   CONSTRAINT `recurring_expenses_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE | ||||||
|  | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; | ||||||
|  | /*!40101 SET character_set_client = @saved_cs_client */; | ||||||
| DROP TABLE IF EXISTS `recurring_invoice_invitations`; | DROP TABLE IF EXISTS `recurring_invoice_invitations`; | ||||||
| /*!40101 SET @saved_cs_client     = @@character_set_client */; | /*!40101 SET @saved_cs_client     = @@character_set_client */; | ||||||
| /*!40101 SET character_set_client = utf8 */; | /*!40101 SET character_set_client = utf8 */; | ||||||
| @ -1481,6 +1551,41 @@ CREATE TABLE `recurring_invoices` ( | |||||||
|   CONSTRAINT `recurring_invoices_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE |   CONSTRAINT `recurring_invoices_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE | ||||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; | ||||||
| /*!40101 SET character_set_client = @saved_cs_client */; | /*!40101 SET character_set_client = @saved_cs_client */; | ||||||
|  | DROP TABLE IF EXISTS `recurring_quote_invitations`; | ||||||
|  | /*!40101 SET @saved_cs_client     = @@character_set_client */; | ||||||
|  | /*!40101 SET character_set_client = utf8 */; | ||||||
|  | CREATE TABLE `recurring_quote_invitations` ( | ||||||
|  |   `id` int(10) unsigned NOT NULL AUTO_INCREMENT, | ||||||
|  |   `company_id` int(10) unsigned NOT NULL, | ||||||
|  |   `user_id` int(10) unsigned NOT NULL, | ||||||
|  |   `client_contact_id` int(10) unsigned NOT NULL, | ||||||
|  |   `recurring_quote_id` int(10) unsigned NOT NULL, | ||||||
|  |   `key` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL, | ||||||
|  |   `transaction_reference` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, | ||||||
|  |   `message_id` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, | ||||||
|  |   `email_error` mediumtext COLLATE utf8mb4_unicode_ci, | ||||||
|  |   `signature_base64` text COLLATE utf8mb4_unicode_ci, | ||||||
|  |   `signature_date` datetime DEFAULT NULL, | ||||||
|  |   `sent_date` datetime DEFAULT NULL, | ||||||
|  |   `viewed_date` datetime DEFAULT NULL, | ||||||
|  |   `opened_date` datetime DEFAULT NULL, | ||||||
|  |   `email_status` enum('delivered','bounced','spam') COLLATE utf8mb4_unicode_ci DEFAULT NULL, | ||||||
|  |   `created_at` timestamp(6) NULL DEFAULT NULL, | ||||||
|  |   `updated_at` timestamp(6) NULL DEFAULT NULL, | ||||||
|  |   `deleted_at` timestamp(6) NULL DEFAULT NULL, | ||||||
|  |   PRIMARY KEY (`id`), | ||||||
|  |   UNIQUE KEY `cli_rec_q` (`client_contact_id`,`recurring_quote_id`), | ||||||
|  |   KEY `recurring_quote_invitations_user_id_foreign` (`user_id`), | ||||||
|  |   KEY `recurring_quote_invitations_company_id_foreign` (`company_id`), | ||||||
|  |   KEY `rec_co_del_q` (`deleted_at`,`recurring_quote_id`,`company_id`), | ||||||
|  |   KEY `recurring_quote_invitations_recurring_quote_id_index` (`recurring_quote_id`), | ||||||
|  |   KEY `recurring_quote_invitations_key_index` (`key`), | ||||||
|  |   CONSTRAINT `recurring_quote_invitations_client_contact_id_foreign` FOREIGN KEY (`client_contact_id`) REFERENCES `client_contacts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, | ||||||
|  |   CONSTRAINT `recurring_quote_invitations_company_id_foreign` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, | ||||||
|  |   CONSTRAINT `recurring_quote_invitations_recurring_quote_id_foreign` FOREIGN KEY (`recurring_quote_id`) REFERENCES `recurring_invoices` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, | ||||||
|  |   CONSTRAINT `recurring_quote_invitations_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE | ||||||
|  | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; | ||||||
|  | /*!40101 SET character_set_client = @saved_cs_client */; | ||||||
| DROP TABLE IF EXISTS `recurring_quotes`; | DROP TABLE IF EXISTS `recurring_quotes`; | ||||||
| /*!40101 SET @saved_cs_client     = @@character_set_client */; | /*!40101 SET @saved_cs_client     = @@character_set_client */; | ||||||
| /*!40101 SET character_set_client = utf8 */; | /*!40101 SET character_set_client = utf8 */; | ||||||
| @ -1521,13 +1626,29 @@ CREATE TABLE `recurring_quotes` ( | |||||||
|   `balance` decimal(20,6) NOT NULL DEFAULT '0.000000', |   `balance` decimal(20,6) NOT NULL DEFAULT '0.000000', | ||||||
|   `last_viewed` datetime DEFAULT NULL, |   `last_viewed` datetime DEFAULT NULL, | ||||||
|   `frequency_id` int(10) unsigned NOT NULL, |   `frequency_id` int(10) unsigned NOT NULL, | ||||||
|   `start_date` date DEFAULT NULL, |  | ||||||
|   `last_sent_date` datetime DEFAULT NULL, |   `last_sent_date` datetime DEFAULT NULL, | ||||||
|   `next_send_date` datetime DEFAULT NULL, |   `next_send_date` datetime DEFAULT NULL, | ||||||
|   `remaining_cycles` int(10) unsigned DEFAULT NULL, |   `remaining_cycles` int(10) unsigned DEFAULT NULL, | ||||||
|   `created_at` timestamp(6) NULL DEFAULT NULL, |   `created_at` timestamp(6) NULL DEFAULT NULL, | ||||||
|   `updated_at` timestamp(6) NULL DEFAULT NULL, |   `updated_at` timestamp(6) NULL DEFAULT NULL, | ||||||
|   `deleted_at` timestamp(6) NULL DEFAULT NULL, |   `deleted_at` timestamp(6) NULL DEFAULT NULL, | ||||||
|  |   `auto_bill` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'off', | ||||||
|  |   `auto_bill_enabled` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|  |   `paid_to_date` decimal(20,6) NOT NULL DEFAULT '0.000000', | ||||||
|  |   `custom_surcharge1` decimal(20,6) DEFAULT NULL, | ||||||
|  |   `custom_surcharge2` decimal(20,6) DEFAULT NULL, | ||||||
|  |   `custom_surcharge3` decimal(20,6) DEFAULT NULL, | ||||||
|  |   `custom_surcharge4` decimal(20,6) DEFAULT NULL, | ||||||
|  |   `custom_surcharge_tax1` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|  |   `custom_surcharge_tax2` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|  |   `custom_surcharge_tax3` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|  |   `custom_surcharge_tax4` tinyint(1) NOT NULL DEFAULT '0', | ||||||
|  |   `due_date_days` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL, | ||||||
|  |   `exchange_rate` decimal(13,6) NOT NULL DEFAULT '1.000000', | ||||||
|  |   `partial` decimal(16,4) DEFAULT NULL, | ||||||
|  |   `partial_due_date` date DEFAULT NULL, | ||||||
|  |   `subscription_id` int(10) unsigned DEFAULT NULL, | ||||||
|  |   `uses_inclusive_taxes` tinyint(1) NOT NULL DEFAULT '1', | ||||||
|   PRIMARY KEY (`id`), |   PRIMARY KEY (`id`), | ||||||
|   KEY `recurring_quotes_company_id_deleted_at_index` (`company_id`,`deleted_at`), |   KEY `recurring_quotes_company_id_deleted_at_index` (`company_id`,`deleted_at`), | ||||||
|   KEY `recurring_quotes_user_id_foreign` (`user_id`), |   KEY `recurring_quotes_user_id_foreign` (`user_id`), | ||||||
| @ -1973,3 +2094,25 @@ INSERT INTO `migrations` VALUES (91,'2021_08_10_034407_add_more_languages',4); | |||||||
| INSERT INTO `migrations` VALUES (92,'2021_08_18_220124_use_comma_as_decimal_place_companies_table',4); | INSERT INTO `migrations` VALUES (92,'2021_08_18_220124_use_comma_as_decimal_place_companies_table',4); | ||||||
| INSERT INTO `migrations` VALUES (93,'2021_08_24_115919_update_designs',4); | INSERT INTO `migrations` VALUES (93,'2021_08_24_115919_update_designs',4); | ||||||
| INSERT INTO `migrations` VALUES (94,'2021_08_25_093105_report_include_drafts_in_companies_table',5); | INSERT INTO `migrations` VALUES (94,'2021_08_25_093105_report_include_drafts_in_companies_table',5); | ||||||
|  | INSERT INTO `migrations` VALUES (95,'2021_08_14_054458_square_payment_driver',6); | ||||||
|  | INSERT INTO `migrations` VALUES (96,'2021_08_23_101529_recurring_expenses_schema',6); | ||||||
|  | INSERT INTO `migrations` VALUES (97,'2021_09_05_101209_update_braintree_gateway',6); | ||||||
|  | INSERT INTO `migrations` VALUES (98,'2021_09_20_233053_set_square_test_mode_boolean',6); | ||||||
|  | INSERT INTO `migrations` VALUES (99,'2021_09_23_100629_add_currencies',6); | ||||||
|  | INSERT INTO `migrations` VALUES (100,'2021_09_24_201319_add_mollie_bank_transfer_to_payment_types',6); | ||||||
|  | INSERT INTO `migrations` VALUES (101,'2021_09_24_211504_add_kbc_to_payment_types',6); | ||||||
|  | INSERT INTO `migrations` VALUES (102,'2021_09_24_213858_add_bancontact_to_payment_types',6); | ||||||
|  | INSERT INTO `migrations` VALUES (103,'2021_09_28_154647_activate_gocardless_payment_driver',6); | ||||||
|  | INSERT INTO `migrations` VALUES (104,'2021_09_29_190258_add_required_client_registration_fields',6); | ||||||
|  | INSERT INTO `migrations` VALUES (105,'2021_10_04_134908_add_ideal_to_payment_types',6); | ||||||
|  | INSERT INTO `migrations` VALUES (106,'2021_10_06_044800_updated_bold_and_modern_designs',6); | ||||||
|  | INSERT INTO `migrations` VALUES (107,'2021_10_07_141737_razorpay',6); | ||||||
|  | INSERT INTO `migrations` VALUES (108,'2021_10_07_155410_add_hosted_page_to_payment_types',6); | ||||||
|  | INSERT INTO `migrations` VALUES (109,'2021_10_15_00000_stripe_payment_gateways',6); | ||||||
|  | INSERT INTO `migrations` VALUES (110,'2021_10_16_135200_add_direct_debit_to_payment_types',6); | ||||||
|  | INSERT INTO `migrations` VALUES (111,'2021_10_19_142200_add_gateway_type_for_direct_debit',6); | ||||||
|  | INSERT INTO `migrations` VALUES (112,'2021_10_20_005529_add_filename_to_backups_table',6); | ||||||
|  | INSERT INTO `migrations` VALUES (113,'2021_11_08_131308_onboarding',6); | ||||||
|  | INSERT INTO `migrations` VALUES (114,'2021_11_09_115919_update_designs',6); | ||||||
|  | INSERT INTO `migrations` VALUES (115,'2021_11_10_184847_add_is_migrate_column_to_accounts_table',6); | ||||||
|  | INSERT INTO `migrations` VALUES (116,'2021_11_11_163121_add_instant_bank_transfer',7); | ||||||
|  | |||||||
| @ -44,7 +44,7 @@ class PaymentLibrariesSeeder extends Seeder | |||||||
|             ['id' => 17, 'name' => 'Pin', 'provider' => 'Pin', 'key' => '0749cb92a6b36c88bd9ff8aabd2efcab', 'fields' => '{"secretKey":"","testMode":false}'], |             ['id' => 17, 'name' => 'Pin', 'provider' => 'Pin', 'key' => '0749cb92a6b36c88bd9ff8aabd2efcab', 'fields' => '{"secretKey":"","testMode":false}'], | ||||||
|             ['id' => 18, 'name' => 'SagePay Direct', 'provider' => 'SagePay_Direct', 'key' => '4c8f4e5d0f353a122045eb9a60cc0f2d', 'fields' => '{"vendor":"","testMode":false,"referrerId":""}'], |             ['id' => 18, 'name' => 'SagePay Direct', 'provider' => 'SagePay_Direct', 'key' => '4c8f4e5d0f353a122045eb9a60cc0f2d', 'fields' => '{"vendor":"","testMode":false,"referrerId":""}'], | ||||||
|             ['id' => 19, 'name' => 'SecurePay DirectPost', 'provider' => 'SecurePay_DirectPost', 'key' => '8036a5aadb2bdaafb23502da8790b6a2', 'fields' => '{"merchantId":"","transactionPassword":"","testMode":false,"enable_ach":"","enable_sofort":"","enable_apple_pay":"","enable_alipay":""}'], |             ['id' => 19, 'name' => 'SecurePay DirectPost', 'provider' => 'SecurePay_DirectPost', 'key' => '8036a5aadb2bdaafb23502da8790b6a2', 'fields' => '{"merchantId":"","transactionPassword":"","testMode":false,"enable_ach":"","enable_sofort":"","enable_apple_pay":"","enable_alipay":""}'], | ||||||
|             ['id' => 20, 'name' => 'Stripe', 'provider' => 'Stripe', 'sort_order' => 1, 'key' => 'd14dd26a37cecc30fdd65700bfb55b23', 'fields' => '{"apiKey":"", "publishableKey":""}'], |             ['id' => 20, 'name' => 'Stripe', 'provider' => 'Stripe', 'sort_order' => 1, 'key' => 'd14dd26a37cecc30fdd65700bfb55b23', 'fields' => '{"publishableKey":"","apiKey":""}'], | ||||||
|             ['id' => 21, 'name' => 'TargetPay Direct eBanking', 'provider' => 'TargetPay_Directebanking', 'key' => 'd14dd26a37cdcc30fdd65700bfb55b23', 'fields' => '{"subAccountId":""}'], |             ['id' => 21, 'name' => 'TargetPay Direct eBanking', 'provider' => 'TargetPay_Directebanking', 'key' => 'd14dd26a37cdcc30fdd65700bfb55b23', 'fields' => '{"subAccountId":""}'], | ||||||
|             ['id' => 22, 'name' => 'TargetPay Ideal', 'provider' => 'TargetPay_Ideal', 'key' => 'ea3b328bd72d381387281c3bd83bd97c', 'fields' => '{"subAccountId":""}'], |             ['id' => 22, 'name' => 'TargetPay Ideal', 'provider' => 'TargetPay_Ideal', 'key' => 'ea3b328bd72d381387281c3bd83bd97c', 'fields' => '{"subAccountId":""}'], | ||||||
|             ['id' => 23, 'name' => 'TargetPay Mr Cash', 'provider' => 'TargetPay_Mrcash', 'key' => 'a0035fc0d87c4950fb82c73e2fcb825a', 'fields' => '{"subAccountId":""}'], |             ['id' => 23, 'name' => 'TargetPay Mr Cash', 'provider' => 'TargetPay_Mrcash', 'key' => 'a0035fc0d87c4950fb82c73e2fcb825a', 'fields' => '{"subAccountId":""}'], | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ | |||||||
|   <php> |   <php> | ||||||
|     <env name="APP_ENV" value="testing"/> |     <env name="APP_ENV" value="testing"/> | ||||||
|     <env name="BCRYPT_ROUNDS" value="4"/> |     <env name="BCRYPT_ROUNDS" value="4"/> | ||||||
|     <env name="CACHE_DRIVER" value="array"/> |     <env name="CACHE_DRIVER" value="file"/> | ||||||
|     <env name="SESSION_DRIVER" value="array"/> |     <env name="SESSION_DRIVER" value="array"/> | ||||||
|     <env name="QUEUE_CONNECTION" value="sync"/> |     <env name="QUEUE_CONNECTION" value="sync"/> | ||||||
|     <env name="MAIL_MAILER" value="array"/> |     <env name="MAIL_MAILER" value="array"/> | ||||||
|  | |||||||
| @ -6543,6 +6543,34 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
| SOFTWARE. | SOFTWARE. | ||||||
|  | -------------------------------------------------------------------------------- | ||||||
|  | diacritic | ||||||
|  | 
 | ||||||
|  | Copyright (c) 2016, Agilord. | ||||||
|  | All rights reserved. | ||||||
|  | 
 | ||||||
|  | Redistribution and use in source and binary forms, with or without | ||||||
|  | modification, are permitted provided that the following conditions are met: | ||||||
|  |     * Redistributions of source code must retain the above copyright | ||||||
|  |       notice, this list of conditions and the following disclaimer. | ||||||
|  |     * Redistributions in binary form must reproduce the above copyright | ||||||
|  |       notice, this list of conditions and the following disclaimer in the | ||||||
|  |       documentation and/or other materials provided with the distribution. | ||||||
|  |     * Neither the name of the <organization> nor the | ||||||
|  |       names of its contributors may be used to endorse or promote products | ||||||
|  |       derived from this software without specific prior written permission. | ||||||
|  | 
 | ||||||
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||||
|  | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||||
|  | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
|  | DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | ||||||
|  | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||||
|  | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||||
|  | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||||
|  | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||||
|  | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | 
 | ||||||
| -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||||||
| double-conversion | double-conversion | ||||||
| icu | icu | ||||||
|  | |||||||
							
								
								
									
										46
									
								
								public/flutter_service_worker.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								public/flutter_service_worker.js
									
									
									
									
										vendored
									
									
								
							| @ -3,38 +3,38 @@ const MANIFEST = 'flutter-app-manifest'; | |||||||
| const TEMP = 'flutter-temp-cache'; | const TEMP = 'flutter-temp-cache'; | ||||||
| const CACHE_NAME = 'flutter-app-cache'; | const CACHE_NAME = 'flutter-app-cache'; | ||||||
| const RESOURCES = { | const RESOURCES = { | ||||||
|   "manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40", |   "favicon.ico": "51636d3a390451561744c42188ccd628", | ||||||
| "version.json": "9c7b0edc83733da56c726678aacd9fd3", | "version.json": "f01b70a1dd8b65dd69abd55a4fe54b83", | ||||||
| "icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed", | "manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40", | ||||||
| "icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35", | "icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35", | ||||||
|  | "icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed", | ||||||
|  | "main.dart.js": "03d6faff8d468318196cd0bef8a4c9a6", | ||||||
| "favicon.png": "dca91c54388f52eded692718d5a98b8b", | "favicon.png": "dca91c54388f52eded692718d5a98b8b", | ||||||
| "favicon.ico": "51636d3a390451561744c42188ccd628", | "/": "c2e105029a9aed730c6480128daf2ced", | ||||||
| "main.dart.js": "40a468819694baa11ae02390609712fc", |  | ||||||
| "/": "38d8084156eb614c31d736ce8c9bd255", |  | ||||||
| "assets/NOTICES": "5a96be85b952e4fcd3a6965546c85b7f", |  | ||||||
| "assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "015400679694f1f51047e46da0e1dc98", |  | ||||||
| "assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5", |  | ||||||
| "assets/fonts/MaterialIcons-Regular.otf": "4e6447691c9509f7acdbf8a931a85ca1", |  | ||||||
| "assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f", | "assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f", | ||||||
|  | "assets/fonts/MaterialIcons-Regular.otf": "4e6447691c9509f7acdbf8a931a85ca1", | ||||||
|  | "assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5", | ||||||
| "assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219", | "assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219", | ||||||
| "assets/assets/images/logo_dark.png": "a233ed1d4d0f7414bf97a9a10f11fb0a", |  | ||||||
| "assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541", |  | ||||||
| "assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1", |  | ||||||
| "assets/assets/images/payment_types/maestro.png": "e533b92bfb50339fdbfa79e3dfe81f08", |  | ||||||
| "assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6", |  | ||||||
| "assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024", | "assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024", | ||||||
| "assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629", | "assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc", | ||||||
| "assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2", | "assets/assets/images/payment_types/maestro.png": "e533b92bfb50339fdbfa79e3dfe81f08", | ||||||
| "assets/assets/images/payment_types/discover.png": "6c0a386a00307f87db7bea366cca35f5", |  | ||||||
| "assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c", | "assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c", | ||||||
| "assets/assets/images/payment_types/carteblanche.png": "d936e11fa3884b8c9f1bd5c914be8629", | "assets/assets/images/payment_types/carteblanche.png": "d936e11fa3884b8c9f1bd5c914be8629", | ||||||
| "assets/assets/images/payment_types/laser.png": "b4e6e93dd35517ac429301119ff05868", | "assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1", | ||||||
| "assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf", | "assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf", | ||||||
| "assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71", | "assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629", | ||||||
| "assets/assets/images/payment_types/amex.png": "c49a4247984b3732a4af50a3390aa978", |  | ||||||
| "assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc", |  | ||||||
| "assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3", | "assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3", | ||||||
| "assets/assets/images/google_logo.png": "0f118259ce403274f407f5e982e681c3" | "assets/assets/images/payment_types/discover.png": "6c0a386a00307f87db7bea366cca35f5", | ||||||
|  | "assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2", | ||||||
|  | "assets/assets/images/payment_types/amex.png": "c49a4247984b3732a4af50a3390aa978", | ||||||
|  | "assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71", | ||||||
|  | "assets/assets/images/payment_types/laser.png": "b4e6e93dd35517ac429301119ff05868", | ||||||
|  | "assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6", | ||||||
|  | "assets/assets/images/google_logo.png": "0f118259ce403274f407f5e982e681c3", | ||||||
|  | "assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541", | ||||||
|  | "assets/assets/images/logo_dark.png": "a233ed1d4d0f7414bf97a9a10f11fb0a", | ||||||
|  | "assets/NOTICES": "4aea723d13add566ca34288c8295b0a4", | ||||||
|  | "assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "015400679694f1f51047e46da0e1dc98" | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // The application shell files that are downloaded before a service worker can
 | // The application shell files that are downloaded before a service worker can
 | ||||||
|  | |||||||
							
								
								
									
										192483
									
								
								public/main.dart.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										192483
									
								
								public/main.dart.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										212448
									
								
								public/main.foss.dart.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										212448
									
								
								public/main.foss.dart.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										190717
									
								
								public/main.html.dart.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										190717
									
								
								public/main.html.dart.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										212320
									
								
								public/main.next.dart.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										212320
									
								
								public/main.next.dart.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										6874
									
								
								public/main.profile.dart.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6874
									
								
								public/main.profile.dart.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								public/vendor/livewire/livewire.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								public/vendor/livewire/livewire.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								public/vendor/livewire/livewire.js.map
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								public/vendor/livewire/livewire.js.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								public/vendor/livewire/manifest.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								public/vendor/livewire/manifest.json
									
									
									
									
										vendored
									
									
								
							| @ -1 +1 @@ | |||||||
| {"/livewire.js":"/livewire.js?id=21fa1dd78491a49255cd"} | {"/livewire.js":"/livewire.js?id=ece4c4ab4b746f6f1739"} | ||||||
| @ -1 +1 @@ | |||||||
| {"app_name":"invoiceninja_flutter","version":"5.0.67","build_number":"67"} | {"app_name":"invoiceninja_flutter","version":"5.0.68","build_number":"68"} | ||||||
| @ -113,7 +113,7 @@ | |||||||
|         table-layout: fixed; |         table-layout: fixed; | ||||||
|         overflow-wrap: break-word; |         overflow-wrap: break-word; | ||||||
|         margin-top: 3rem; |         margin-top: 3rem; | ||||||
|         margin-bottom: 200px; |         margin-bottom: 0px; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     [data-ref="table"]:last-child{ |     [data-ref="table"]:last-child{ | ||||||
| @ -371,20 +371,24 @@ | |||||||
| $entity_images | $entity_images | ||||||
| 
 | 
 | ||||||
| <div id="footer"> | <div id="footer"> | ||||||
|     <div> |     <div style="width: 100%;"> | ||||||
|         <p data-ref="total_table-footer">$entity_footer</p> |         <p data-ref="total_table-footer">$entity_footer</p> | ||||||
| 
 | 
 | ||||||
|         <script> |         <script> | ||||||
|             // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. |             // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. | ||||||
|             document.addEventListener('DOMContentLoaded', () => { |             document.addEventListener('DOMContentLoaded', () => { | ||||||
|                 let tables = [ |                 let tables = [ | ||||||
|                     'product-table', 'task-table', 'delivery-note-table',  'statement-invoice-table-totals', 'statement-payment-table-totals','statement-invoice-table-totals', |                     'product-table', 'task-table', 'delivery-note-table', | ||||||
|                     'statement-invoice-table', 'statement-payment-table', 'statement-aging-table', 'statement-aging-table-totals', 'statement-payment-table-totals' |                     'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals', | ||||||
|  |                     'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table' | ||||||
|                 ]; |                 ]; | ||||||
| 
 | 
 | ||||||
|                 tables.forEach((tableIdentifier) => { |                 tables.forEach((tableIdentifier) => { | ||||||
|                     const el =document.getElementById(tableIdentifier); |                     console.log(document.getElementById(tableIdentifier)); | ||||||
|                     if(el && el.childElementCount === 0)el.remove() | 
 | ||||||
|  |                     document.getElementById(tableIdentifier)?.childElementCount === 0 | ||||||
|  |                         ? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important') | ||||||
|  |                         : ''; | ||||||
|                 }); |                 }); | ||||||
|             }); |             }); | ||||||
|         </script> |         </script> | ||||||
|  | |||||||
| @ -351,7 +351,7 @@ $entity_images | |||||||
| 
 | 
 | ||||||
| <div class="repeating-footer" id="footer"> | <div class="repeating-footer" id="footer"> | ||||||
|     <p data-ref="total_table-footer">$entity_footer</p> |     <p data-ref="total_table-footer">$entity_footer</p> | ||||||
| </div> | 
 | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
|     // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. |     // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. | ||||||
| @ -368,3 +368,5 @@ $entity_images | |||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
| </script> | </script> | ||||||
|  | 
 | ||||||
|  | </div> | ||||||
|  | |||||||
| @ -313,20 +313,25 @@ $entity_images | |||||||
| 
 | 
 | ||||||
| <div class="repeating-footer" id="footer"> | <div class="repeating-footer" id="footer"> | ||||||
|    <p data-ref="total_table-footer">$entity_footer</p> |    <p data-ref="total_table-footer">$entity_footer</p> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         <script> | ||||||
|  |             // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. | ||||||
|  |             document.addEventListener('DOMContentLoaded', () => { | ||||||
|  |                 let tables = [ | ||||||
|  |                     'product-table', 'task-table', 'delivery-note-table', | ||||||
|  |                     'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals', | ||||||
|  |                     'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table' | ||||||
|  |                 ]; | ||||||
|  | 
 | ||||||
|  |                 tables.forEach((tableIdentifier) => { | ||||||
|  |                     console.log(document.getElementById(tableIdentifier)); | ||||||
|  | 
 | ||||||
|  |                     document.getElementById(tableIdentifier)?.childElementCount === 0 | ||||||
|  |                         ? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important') | ||||||
|  |                         : ''; | ||||||
|  |                 }); | ||||||
|  |             }); | ||||||
|  |         </script> | ||||||
|  | 
 | ||||||
| </div> | </div> | ||||||
| 
 |  | ||||||
| <script> |  | ||||||
|     // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. |  | ||||||
|     document.addEventListener('DOMContentLoaded', () => { |  | ||||||
|         let tables = [ |  | ||||||
|             'product-table', 'task-table', 'delivery-note-table', |  | ||||||
|             'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals', |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         tables.forEach((tableIdentifier) => { |  | ||||||
|             document.getElementById(tableIdentifier).childElementCount === 0 |  | ||||||
|                 ? document.getElementById(tableIdentifier).style.display = 'none' |  | ||||||
|                 : ''; |  | ||||||
|         }); |  | ||||||
|     }); |  | ||||||
| </script> |  | ||||||
|  | |||||||
| @ -303,24 +303,29 @@ | |||||||
| 
 | 
 | ||||||
| <div class="repeating-header" id="header"></div> | <div class="repeating-header" id="header"></div> | ||||||
| 
 | 
 | ||||||
| <div class="repeating-footer" id="footer"> |  | ||||||
|    <p data-ref="total_table-footer">$entity_footer</p> |  | ||||||
| </div> |  | ||||||
| 
 | 
 | ||||||
| $entity_images | $entity_images | ||||||
| 
 | 
 | ||||||
| <script> | <div class="repeating-footer" id="footer"> | ||||||
|     // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. |    <p data-ref="total_table-footer">$entity_footer</p> | ||||||
|     document.addEventListener('DOMContentLoaded', () => { |  | ||||||
|         let tables = [ |  | ||||||
|             'product-table', 'task-table', 'delivery-note-table', |  | ||||||
|             'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals', |  | ||||||
|         ]; |  | ||||||
| 
 | 
 | ||||||
|         tables.forEach((tableIdentifier) => { | 
 | ||||||
|             document.getElementById(tableIdentifier).childElementCount === 0 |         <script> | ||||||
|                 ? document.getElementById(tableIdentifier).style.display = 'none' |             // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. | ||||||
|                 : ''; |             document.addEventListener('DOMContentLoaded', () => { | ||||||
|         }); |                 let tables = [ | ||||||
|     }); |                     'product-table', 'task-table', 'delivery-note-table', | ||||||
| </script> |                     'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals', | ||||||
|  |                     'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table' | ||||||
|  |                 ]; | ||||||
|  | 
 | ||||||
|  |                 tables.forEach((tableIdentifier) => { | ||||||
|  |                     console.log(document.getElementById(tableIdentifier)); | ||||||
|  | 
 | ||||||
|  |                     document.getElementById(tableIdentifier)?.childElementCount === 0 | ||||||
|  |                         ? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important') | ||||||
|  |                         : ''; | ||||||
|  |                 }); | ||||||
|  |             }); | ||||||
|  |         </script> | ||||||
|  | </div> | ||||||
|  | |||||||
| @ -313,24 +313,30 @@ | |||||||
| 
 | 
 | ||||||
| <div class="repeating-header" id="header"></div> | <div class="repeating-header" id="header"></div> | ||||||
| 
 | 
 | ||||||
| <div class="repeating-footer" id="footer"> |  | ||||||
|    <p data-ref="total_table-footer">$entity_footer</p> |  | ||||||
| </div> |  | ||||||
| 
 | 
 | ||||||
| $entity_images | $entity_images | ||||||
| 
 | 
 | ||||||
| <script> | <div class="repeating-footer" id="footer"> | ||||||
|     // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. |    <p data-ref="total_table-footer">$entity_footer</p> | ||||||
|     document.addEventListener('DOMContentLoaded', () => { | 
 | ||||||
|         let tables = [ |         <script> | ||||||
|             'product-table', 'task-table', 'delivery-note-table', |             // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. | ||||||
|             'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals', |             document.addEventListener('DOMContentLoaded', () => { | ||||||
|         ]; |                 let tables = [ | ||||||
|  |                     'product-table', 'task-table', 'delivery-note-table', | ||||||
|  |                     'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals', | ||||||
|  |                     'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table' | ||||||
|  |                 ]; | ||||||
|  | 
 | ||||||
|  |                 tables.forEach((tableIdentifier) => { | ||||||
|  |                     console.log(document.getElementById(tableIdentifier)); | ||||||
|  | 
 | ||||||
|  |                     document.getElementById(tableIdentifier)?.childElementCount === 0 | ||||||
|  |                         ? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important') | ||||||
|  |                         : ''; | ||||||
|  |                 }); | ||||||
|  |             }); | ||||||
|  |         </script> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|         tables.forEach((tableIdentifier) => { |  | ||||||
|             document.getElementById(tableIdentifier).childElementCount === 0 |  | ||||||
|                 ? document.getElementById(tableIdentifier).style.display = 'none' |  | ||||||
|                 : ''; |  | ||||||
|         }); |  | ||||||
|     }); |  | ||||||
| </script> |  | ||||||
|  | |||||||
| @ -354,30 +354,29 @@ | |||||||
| 
 | 
 | ||||||
| <div class="repeating-header" id="header"></div> | <div class="repeating-header" id="header"></div> | ||||||
| 
 | 
 | ||||||
| <div class="repeating-footer" id="footer"> |  | ||||||
|    <p data-ref="total_table-footer">$entity_footer</p> |  | ||||||
| </div> |  | ||||||
| 
 | 
 | ||||||
| $entity_images | $entity_images | ||||||
| 
 | 
 | ||||||
| <script> | <div class="repeating-footer" id="footer"> | ||||||
|     // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. |    <p data-ref="total_table-footer">$entity_footer</p> | ||||||
|     document.addEventListener('DOMContentLoaded', () => { |  | ||||||
|         let tables = [ |  | ||||||
|             'product-table', 'task-table', 'delivery-note-table', |  | ||||||
|             'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals', |  | ||||||
|         ]; |  | ||||||
| 
 | 
 | ||||||
|         tables.forEach((tableIdentifier) => { |         <script> | ||||||
|             document.getElementById(tableIdentifier).childElementCount === 0 |             // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. | ||||||
|                 ? document.getElementById(tableIdentifier).style.display = 'none' |             document.addEventListener('DOMContentLoaded', () => { | ||||||
|                 : ''; |                 let tables = [ | ||||||
|         }); |                     'product-table', 'task-table', 'delivery-note-table', | ||||||
|  |                     'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals', | ||||||
|  |                     'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table' | ||||||
|  |                 ]; | ||||||
|  | 
 | ||||||
|  |                 tables.forEach((tableIdentifier) => { | ||||||
|  |                     console.log(document.getElementById(tableIdentifier)); | ||||||
|  | 
 | ||||||
|  |                     document.getElementById(tableIdentifier)?.childElementCount === 0 | ||||||
|  |                         ? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important') | ||||||
|  |                         : ''; | ||||||
|  |                 }); | ||||||
|  |             }); | ||||||
|  |         </script> | ||||||
|  | </div> | ||||||
| 
 | 
 | ||||||
|         // If we have elements in these tables, we can change label to "Statement" & hide entity details. |  | ||||||
|         if (document.querySelectorAll('#statement-payment-table > tbody, #statement-payment-table > tbody, #statement-aging-table-totals > tbody').length > 0) { |  | ||||||
|             document.querySelector('.entity-label').innerText = '$statement_label'; |  | ||||||
|             document.querySelector('.entity-details-wrapper').style.display = 'none'; |  | ||||||
|         }         |  | ||||||
|     }); |  | ||||||
| </script> |  | ||||||
|  | |||||||
| @ -348,24 +348,28 @@ $entity_images | |||||||
| 
 | 
 | ||||||
| <div id="footer"> | <div id="footer"> | ||||||
|     <div class="footer-content"> |     <div class="footer-content"> | ||||||
|         <div style="width: 70%;"> |         <div style="width: 90%"> | ||||||
|             <p data-ref="total_table-footer">$entity_footer</p> |             <p data-ref="total_table-footer">$entity_footer</p> | ||||||
| 
 | 
 | ||||||
|             <script> |         <script> | ||||||
|                 // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. |             // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. | ||||||
|                 document.addEventListener('DOMContentLoaded', () => { |             document.addEventListener('DOMContentLoaded', () => { | ||||||
|                     let tables = [ |                 let tables = [ | ||||||
|                         'product-table', 'task-table', 'delivery-note-table',  'statement-invoice-table-totals', 'statement-payment-table-totals','statement-invoice-table-totals', |                     'product-table', 'task-table', 'delivery-note-table', | ||||||
|                         'statement-invoice-table', 'statement-payment-table', 'statement-aging-table', 'statement-aging-table-totals', 'statement-payment-table-totals' |                     'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals', | ||||||
|                     ]; |                     'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table' | ||||||
|  |                 ]; | ||||||
| 
 | 
 | ||||||
|                     tables.forEach((tableIdentifier) => { |                 tables.forEach((tableIdentifier) => { | ||||||
|                         document.getElementById(tableIdentifier).childElementCount === 0 |                     console.log(document.getElementById(tableIdentifier)); | ||||||
|                                 ? document.getElementById(tableIdentifier).remove() | 
 | ||||||
|                                 : ''; |                     document.getElementById(tableIdentifier)?.childElementCount === 0 | ||||||
|                     }); |                         ? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important') | ||||||
|  |                         : ''; | ||||||
|                 }); |                 }); | ||||||
|             </script> |             }); | ||||||
|  |         </script> | ||||||
|  |              | ||||||
|         </div> |         </div> | ||||||
|         <div class="footer-company-details-address-wrapper"> |         <div class="footer-company-details-address-wrapper"> | ||||||
|             <div id="company-details"></div> |             <div id="company-details"></div> | ||||||
|  | |||||||
| @ -288,24 +288,27 @@ | |||||||
| 
 | 
 | ||||||
| <div class="repeating-header" id="header"></div> | <div class="repeating-header" id="header"></div> | ||||||
| 
 | 
 | ||||||
| <div class="repeating-footer" id="footer"> |  | ||||||
|    <p data-ref="total_table-footer">$entity_footer</p> |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| $entity_images | $entity_images | ||||||
| 
 | 
 | ||||||
| <script> | <div class="repeating-footer" id="footer"> | ||||||
|     // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. |    <p data-ref="total_table-footer">$entity_footer</p> | ||||||
|     document.addEventListener('DOMContentLoaded', () => { |  | ||||||
|         let tables = [ |  | ||||||
|             'product-table', 'task-table', 'delivery-note-table', |  | ||||||
|             'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals', |  | ||||||
|         ]; |  | ||||||
| 
 | 
 | ||||||
|         tables.forEach((tableIdentifier) => { |         <script> | ||||||
|             document.getElementById(tableIdentifier).childElementCount === 0 |             // Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present. | ||||||
|                 ? document.getElementById(tableIdentifier).style.display = 'none' |             document.addEventListener('DOMContentLoaded', () => { | ||||||
|                 : ''; |                 let tables = [ | ||||||
|         }); |                     'product-table', 'task-table', 'delivery-note-table', | ||||||
|     }); |                     'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals', | ||||||
| </script> |                     'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table' | ||||||
|  |                 ]; | ||||||
|  | 
 | ||||||
|  |                 tables.forEach((tableIdentifier) => { | ||||||
|  |                     console.log(document.getElementById(tableIdentifier)); | ||||||
|  | 
 | ||||||
|  |                     document.getElementById(tableIdentifier)?.childElementCount === 0 | ||||||
|  |                         ? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important') | ||||||
|  |                         : ''; | ||||||
|  |                 }); | ||||||
|  |             }); | ||||||
|  |         </script> | ||||||
|  | </div> | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user