diff --git a/VERSION.txt b/VERSION.txt
index 2ea33cb9e706..6f75c330fa4c 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1 +1 @@
-5.6.17
\ No newline at end of file
+5.6.18
\ No newline at end of file
diff --git a/app/Export/CSV/BaseExport.php b/app/Export/CSV/BaseExport.php
index 2d4d2a5a82a3..d9731c49b680 100644
--- a/app/Export/CSV/BaseExport.php
+++ b/app/Export/CSV/BaseExport.php
@@ -318,6 +318,7 @@ class BaseExport
private function resolvePaymentKey($column, $entity, $transformer)
{
+
if($entity instanceof Payment){
$transformed_payment = $transformer->transform($entity);
diff --git a/app/Http/Controllers/ClientPortal/InvitationController.php b/app/Http/Controllers/ClientPortal/InvitationController.php
index 25fea802d1f5..a1d4949f0175 100644
--- a/app/Http/Controllers/ClientPortal/InvitationController.php
+++ b/app/Http/Controllers/ClientPortal/InvitationController.php
@@ -136,8 +136,11 @@ class InvitationController extends Controller
} 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}), 'silent' => $is_silent])->header('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
}
+ return redirect()->route('client.'.$entity.'.show', [$entity => $this->encodePrimaryKey($invitation->{$key})]);
return redirect()->route('client.'.$entity.'.show', [$entity => $this->encodePrimaryKey($invitation->{$key})])->header('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
}
diff --git a/app/Http/Controllers/ClientPortal/InvoiceController.php b/app/Http/Controllers/ClientPortal/InvoiceController.php
index 838bf1dd1b09..8a0013c6d8f9 100644
--- a/app/Http/Controllers/ClientPortal/InvoiceController.php
+++ b/app/Http/Controllers/ClientPortal/InvoiceController.php
@@ -206,8 +206,6 @@ class InvoiceController extends Controller
$file = $invoice->service()->getInvoicePdf(auth()->guard('contact')->user());
- // return response()->download(file_get_contents(public_path($file)));
-
return response()->streamDownload(function () use ($file) {
echo Storage::get($file);
}, basename($file), ['Content-Type' => 'application/pdf']);
diff --git a/app/Http/Controllers/MigrationController.php b/app/Http/Controllers/MigrationController.php
index 41f82d9fffb9..57b3044f228e 100644
--- a/app/Http/Controllers/MigrationController.php
+++ b/app/Http/Controllers/MigrationController.php
@@ -32,6 +32,8 @@ class MigrationController extends BaseController
{
use DispatchesJobs;
+ public bool $silent_migration = false;
+
public function __construct()
{
parent::__construct();
@@ -260,6 +262,9 @@ class MigrationController extends BaseController
{
nlog('Starting Migration');
+ if($request->has('silent_migration'))
+ $this->silent_migration = true;
+
if ($request->companies) {
//handle Laravel 5.5 UniHTTP
$companies = json_decode($request->companies, 1);
@@ -312,7 +317,9 @@ class MigrationController extends BaseController
$nmo->company = $user->account->companies()->first();
$nmo->settings = $user->account->companies()->first()->settings;
$nmo->to_user = $user;
- NinjaMailerJob::dispatch($nmo, true);
+
+ if(!$this->silent_migration)
+ NinjaMailerJob::dispatch($nmo, true);
return;
} elseif ($existing_company && $company_count > 10) {
@@ -321,7 +328,9 @@ class MigrationController extends BaseController
$nmo->company = $user->account->companies()->first();
$nmo->settings = $user->account->companies()->first()->settings;
$nmo->to_user = $user;
- NinjaMailerJob::dispatch($nmo, true);
+
+ if(!$this->silent_migration)
+ NinjaMailerJob::dispatch($nmo, true);
return;
}
@@ -341,7 +350,8 @@ class MigrationController extends BaseController
$nmo->settings = $user->account->companies()->first();
$nmo->to_user = $user;
- NinjaMailerJob::dispatch($nmo, true);
+ if(!$this->silent_migration)
+ NinjaMailerJob::dispatch($nmo, true);
return response()->json([
'_id' => Str::uuid(),
@@ -431,9 +441,9 @@ class MigrationController extends BaseController
nlog($migration_file);
if (Ninja::isHosted()) {
- StartMigration::dispatch($migration_file, $user, $fresh_company)->onQueue('migration');
+ StartMigration::dispatch($migration_file, $user, $fresh_company, $this->silent_migration)->onQueue('migration');
} else {
- StartMigration::dispatch($migration_file, $user, $fresh_company);
+ StartMigration::dispatch($migration_file, $user, $fresh_company, $this->silent_migration);
}
}
diff --git a/app/Http/Controllers/ProtectedDownloadController.php b/app/Http/Controllers/ProtectedDownloadController.php
index 452989efda9e..d7277d69f383 100644
--- a/app/Http/Controllers/ProtectedDownloadController.php
+++ b/app/Http/Controllers/ProtectedDownloadController.php
@@ -30,11 +30,7 @@ class ProtectedDownloadController extends BaseController
abort(404, 'File no longer available');
}
- UnlinkFile::dispatch(config('filesystems.default'), $hashed_path)->delay(now()->addSeconds(10));
-
- return response()->streamDownload(function () use ($hashed_path) {
- echo Storage::get($hashed_path);
- }, basename($hashed_path), []);
+ return response()->download($hashed_path, basename($hashed_path), [])->deleteFileAfterSend(true);
}
diff --git a/app/Http/Controllers/WebCronController.php b/app/Http/Controllers/WebCronController.php
index 81e1633606df..c9607ba4fdec 100644
--- a/app/Http/Controllers/WebCronController.php
+++ b/app/Http/Controllers/WebCronController.php
@@ -26,7 +26,7 @@ class WebCronController extends Controller
* @return Response
*
* @OA\Get(
- * path="/api/v1/webcron",
+ * path="/webcron",
* operationId="webcron",
* tags={"webcron"},
* summary="Executes the task scheduler via a webcron service",
diff --git a/app/Http/Livewire/PdfSlot.php b/app/Http/Livewire/PdfSlot.php
index 9b52146a3412..8eda7b1c4ded 100644
--- a/app/Http/Livewire/PdfSlot.php
+++ b/app/Http/Livewire/PdfSlot.php
@@ -12,8 +12,21 @@
namespace App\Http\Livewire;
-use App\Libraries\MultiDB;
+use App\Utils\Number;
use Livewire\Component;
+use App\Utils\HtmlEngine;
+use App\Libraries\MultiDB;
+use App\Models\QuoteInvitation;
+use App\Utils\VendorHtmlEngine;
+use App\Models\CreditInvitation;
+use App\Services\Pdf\PdfBuilder;
+use App\Services\Pdf\PdfService;
+use App\Models\InvoiceInvitation;
+use App\Services\Pdf\PdfDesigner;
+use App\Services\Pdf\PdfConfiguration;
+use App\Models\PurchaseOrderInvitation;
+use App\Models\RecurringInvoiceInvitation;
+use App\Jobs\Vendor\CreatePurchaseOrderPdf;
class PdfSlot extends Component
{
@@ -27,23 +40,212 @@ class PdfSlot extends Component
public $url;
+ private $settings;
+
+ private $html_variables;
+
+ private $entity_type;
+
+ protected $listeners = ['viewportChanged' => 'getPdf'];
+
public function mount()
{
MultiDB::setDb($this->db);
}
+ public function getPdf()
+ {
+ $this->pdf = $this->entity->fullscreenPdfViewer($this->invitation);
+ }
+
+ public function downloadPdf()
+ {
+
+ $file_name = $this->entity->numberFormatter().'.pdf';
+
+ if($this->entity instanceof \App\Models\PurchaseOrder)
+ $file = (new CreatePurchaseOrderPdf($this->invitation, $this->invitation->company->db))->rawPdf();
+ else
+ $file = (new \App\Jobs\Entity\CreateRawPdf($this->invitation, $this->invitation->company->db))->handle();
+
+ $headers = ['Content-Type' => 'application/pdf'];
+
+ return response()->streamDownload(function () use ($file) {
+ echo $file;
+ }, $file_name, $headers);
+
+ }
+
public function render()
{
+ $this->entity_type = $this->resolveEntityType();
+
+ $this->settings = $this->entity->client ? $this->entity->client->getMergedSettings() : $this->entity->company->settings;
+
+ $this->html_variables = $this->entity->client ?
+ (new HtmlEngine($this->invitation))->generateLabelsAndValues() :
+ (new VendorHtmlEngine($this->invitation))->generateLabelsAndValues();
+
return render('components.livewire.pdf-slot', [
'invitation' => $this->invitation,
'entity' => $this->entity,
+ 'data' => $this->invitation->company->settings,
+ 'entity_type' => $this->entity_type,
+ 'products' => $this->getProducts(),
+ 'services' => $this->getServices(),
+ 'amount' => Number::formatMoney($this->entity->amount, $this->entity->client ?: $this->entity->vendor),
+ 'balance' => Number::formatMoney($this->entity->balance, $this->entity->client ?: $this->entity->vendor),
+ 'company_details' => $this->getCompanyDetails(),
+ 'company_address' => $this->getCompanyAddress(),
+ 'entity_details' => $this->getEntityDetails(),
+ 'user_details' => $this->getUserDetails(),
+ 'user_name' => $this->getUserName(),
+
]);
}
- public function getPdf()
+ private function convertVariables($string): string
{
-
- $this->pdf = $this->entity->fullscreenPdfViewer($this->invitation);
+
+ $html = strtr($string, $this->html_variables['labels']);
+ $html = strtr($html, $this->html_variables['values']);
+
+ return $html;
}
+
+ private function getCompanyAddress()
+ {
+
+ $company_address = "";
+
+ foreach($this->settings->pdf_variables->company_address as $variable) {
+ $company_address .= "
{$variable}
";
+ }
+
+ return $this->convertVariables($company_address);
+
+ }
+
+ private function getCompanyDetails()
+ {
+ $company_details = "";
+
+ foreach($this->settings->pdf_variables->company_details as $variable) {
+ $company_details .= "{$variable}
";
+ }
+
+ return $this->convertVariables($company_details);
+
+ }
+
+ private function getEntityDetails()
+ {
+ $entity_details = "";
+
+ if($this->entity_type == 'invoice' || $this->entity_type == 'recurring_invoice') {
+ foreach($this->settings->pdf_variables->invoice_details as $variable)
+ $entity_details .= "{$variable}_label
{$variable}
";
+
+ }
+ elseif($this->entity_type == 'quote'){
+ foreach($this->settings->pdf_variables->quote_details as $variable)
+ $entity_details .= "{$variable}_label
{$variable}
";
+ }
+ elseif($this->entity_type == 'credit') {
+ foreach($this->settings->pdf_variables->credit_details as $variable)
+ $entity_details .= "{$variable}_label
{$variable}
";
+ }
+ elseif($this->entity_type == 'purchase_order'){
+ foreach($this->settings->pdf_variables->purchase_order_details as $variable)
+ $entity_details .= "{$variable}_label
{$variable}
";
+ }
+
+ return $this->convertVariables($entity_details);
+
+ }
+
+ private function getUserName()
+ {
+ $name = ctrans('texts.details');
+
+ if($this->entity_type == 'purchase_order' && isset($this->settings->pdf_variables->vendor_details[0])) {
+ $name = $this->settings->pdf_variables->vendor_details[0];
+
+ } elseif(isset($this->settings->pdf_variables->client_details[0])) {
+
+ $name = $this->settings->pdf_variables->client_details[0];
+ }
+
+ return $this->convertVariables($name);
+
+ }
+
+ private function getUserDetails()
+ {
+ $user_details = "";
+
+ if($this->entity_type == 'purchase_order') {
+ foreach(array_slice($this->settings->pdf_variables->vendor_details,1) as $variable) {
+ $user_details .= "{$variable}
";
+ }
+ }
+ else{
+ foreach(array_slice($this->settings->pdf_variables->client_details,1) as $variable) {
+ $user_details .= "{$variable}
";
+ }
+ }
+
+ return $this->convertVariables($user_details);
+ }
+
+ private function getProducts()
+ {
+ $product_items = collect($this->entity->line_items)->filter(function ($item) {
+ return $item->type_id == 1 || $item->type_id == 6 || $item->type_id == 5;
+ })->map(function ($item){
+ return [
+ 'quantity' => $item->quantity,
+ 'cost' => Number::formatMoney($item->cost, $this->entity->client ?: $this->entity->vendor),
+ 'notes' => $item->notes,
+ 'line_total' => Number::formatMoney($item->line_total, $this->entity->client ?: $this->entity->vendor),
+ ];
+ });
+
+ return $product_items;
+ }
+
+ private function getServices()
+ {
+ $task_items = collect($this->entity->line_items)->filter(function ($item) {
+ return $item->type_id == 2;
+ })->map(function ($item){
+ return [
+ 'quantity' => $item->quantity,
+ 'cost' => Number::formatMoney($item->cost, $this->entity->client ?: $this->entity->vendor),
+ 'notes' => $item->notes,
+ 'line_total' => Number::formatMoney($item->line_total, $this->entity->client ?: $this->entity->vendor),
+ ];
+ });
+
+ return $task_items;
+
+ }
+
+ private function resolveEntityType() :string
+ {
+ if ($this->invitation instanceof InvoiceInvitation) {
+ return 'invoice';
+ } elseif ($this->invitation instanceof QuoteInvitation) {
+ return 'quote';
+ } elseif ($this->invitation instanceof CreditInvitation) {
+ return 'credit';
+ } elseif ($this->invitation instanceof RecurringInvoiceInvitation) {
+ return 'recurring_invoice';
+ } elseif ($this->invitation instanceof PurchaseOrderInvitation) {
+ return 'purchase_order';
+ }
+
+ return '';
+ }
}
diff --git a/app/Http/Requests/Invoice/BulkInvoiceRequest.php b/app/Http/Requests/Invoice/BulkInvoiceRequest.php
index 738a8f7bd762..68554d1ee71d 100644
--- a/app/Http/Requests/Invoice/BulkInvoiceRequest.php
+++ b/app/Http/Requests/Invoice/BulkInvoiceRequest.php
@@ -24,7 +24,7 @@ class BulkInvoiceRequest extends Request
{
return [
'action' => 'required|string',
- 'ids' => 'required',
+ 'ids' => 'required|array',
'email_type' => 'sometimes|in:reminder1,reminder2,reminder3,reminder_endless,custom1,custom2,custom3,invoice,quote,credit,payment,payment_partial,statement,purchase_order'
];
}
diff --git a/app/Jobs/Invoice/BulkInvoiceJob.php b/app/Jobs/Invoice/BulkInvoiceJob.php
index dfbdb18a7905..be2224d12378 100644
--- a/app/Jobs/Invoice/BulkInvoiceJob.php
+++ b/app/Jobs/Invoice/BulkInvoiceJob.php
@@ -41,7 +41,7 @@ class BulkInvoiceJob implements ShouldQueue
*/
public function handle()
{ //only the reminder should mark the reminder sent field
- // $this->invoice->service()->touchReminder($this->reminder_template)->markSent()->save();
+
$this->invoice->service()->markSent()->save();
$this->invoice->invitations->load('contact.client.country', 'invoice.client.country', 'invoice.company')->each(function ($invitation) {
diff --git a/app/Jobs/Subscription/CleanStaleInvoiceOrder.php b/app/Jobs/Subscription/CleanStaleInvoiceOrder.php
index f872b467f636..b182a8831c1f 100644
--- a/app/Jobs/Subscription/CleanStaleInvoiceOrder.php
+++ b/app/Jobs/Subscription/CleanStaleInvoiceOrder.php
@@ -56,7 +56,7 @@ class CleanStaleInvoiceOrder implements ShouldQueue
Invoice::query()
->withTrashed()
->where('status_id', Invoice::STATUS_SENT)
- ->where('created_at', '<', now()->subHours(2))
+ ->whereBetween('created_at', [now()->subHours(1), now()->subMinutes(10)])
->where('balance', '>', 0)
->cursor()
->each(function ($invoice){
@@ -77,7 +77,7 @@ class CleanStaleInvoiceOrder implements ShouldQueue
Invoice::query()
->withTrashed()
->where('is_proforma', 1)
- ->where('created_at', '<', now()->subHour())
+ ->whereBetween('created_at', [now()->subHours(1), now()->subMinutes(10)])
->cursor()
->each(function ($invoice) use ($repo) {
$invoice->is_proforma = false;
diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php
index b45f3ead4cfa..e4de8ecc5244 100644
--- a/app/Jobs/Util/Import.php
+++ b/app/Jobs/Util/Import.php
@@ -165,6 +165,8 @@ class Import implements ShouldQueue
public $timeout = 10000000;
+ public $silent_migration;
+
// public $backoff = 86430;
// public $maxExceptions = 2;
@@ -176,12 +178,13 @@ class Import implements ShouldQueue
* @param User $user
* @param array $resources
*/
- public function __construct(string $file_path, Company $company, User $user, array $resources = [])
+ public function __construct(string $file_path, Company $company, User $user, array $resources = [], $silent_migration = false)
{
$this->file_path = $file_path;
$this->company = $company;
$this->user = $user;
$this->resources = $resources;
+ $this->silent_migration = $silent_migration;
}
public function middleware()
@@ -263,8 +266,9 @@ class Import implements ShouldQueue
$t = app('translator');
$t->replace(Ninja::transformTranslations($this->company->settings));
- Mail::to($this->user->email, $this->user->name())
- ->send(new MigrationCompleted($this->company->id, $this->company->db, implode(" ", $check_data)));
+ if(!$this->silent_migration)
+ Mail::to($this->user->email, $this->user->name())->send(new MigrationCompleted($this->company->id, $this->company->db, implode(" ", $check_data)));
+
} catch(\Exception $e) {
nlog($e->getMessage());
}
@@ -641,7 +645,6 @@ class Import implements ShouldQueue
$user = $user_repository->save($modified, $this->fetchUser($resource['email']), true, true);
$user->email_verified_at = now();
- // $user->confirmation_code = '';
if ($modified['deleted_at']) {
$user->deleted_at = now();
@@ -1590,7 +1593,9 @@ class Import implements ShouldQueue
$nmo->company = $this->company;
$nmo->settings = $this->company->settings;
$nmo->to_user = $this->user;
- NinjaMailerJob::dispatch($nmo, true);
+
+ if(!$this->silent_migration)
+ NinjaMailerJob::dispatch($nmo, true);
$modified['gateway_key'] = 'd14dd26a47cecc30fdd65700bfb67b34';
}
diff --git a/app/Jobs/Util/ReminderJob.php b/app/Jobs/Util/ReminderJob.php
index 879b759204fd..80f2676d2ab5 100644
--- a/app/Jobs/Util/ReminderJob.php
+++ b/app/Jobs/Util/ReminderJob.php
@@ -99,7 +99,6 @@ class ReminderJob implements ShouldQueue
$query->where('is_disabled', 0);
})
->with('invitations')->chunk(50, function ($invoices) {
- // if ($invoice->refresh() && $invoice->isPayable()) {
foreach ($invoices as $invoice) {
$this->sendReminderForInvoice($invoice);
diff --git a/app/Jobs/Util/StartMigration.php b/app/Jobs/Util/StartMigration.php
index a76afefb05f3..432b1c1b8be4 100644
--- a/app/Jobs/Util/StartMigration.php
+++ b/app/Jobs/Util/StartMigration.php
@@ -49,6 +49,8 @@ class StartMigration implements ShouldQueue
*/
private $company;
+ private $silent_migration;
+
/**
* Create a new job instance.
*
@@ -60,11 +62,12 @@ class StartMigration implements ShouldQueue
public $timeout = 0;
- public function __construct($filepath, User $user, Company $company)
+ public function __construct($filepath, User $user, Company $company, $silent_migration = false)
{
$this->filepath = $filepath;
$this->user = $user;
$this->company = $company;
+ $this->silent_migration = $silent_migration;
}
/**
@@ -116,7 +119,7 @@ class StartMigration implements ShouldQueue
throw new NonExistingMigrationFile('Migration file does not exist, or it is corrupted.');
}
- (new Import($file, $this->company, $this->user))->handle();
+ (new Import($file, $this->company, $this->user, [], $this->silent_migration))->handle();
Storage::deleteDirectory(public_path("storage/migrations/{$filename}"));
@@ -138,7 +141,8 @@ class StartMigration implements ShouldQueue
app('sentry')->captureException($e);
}
- Mail::to($this->user->email, $this->user->name())->send(new MigrationFailed($e, $this->company, $e->getMessage()));
+ if(!$this->silent_migration)
+ Mail::to($this->user->email, $this->user->name())->send(new MigrationFailed($e, $this->company, $e->getMessage()));
if (Ninja::isHosted()) {
$migration_failed = new MigrationFailed($e, $this->company, $e->getMessage());
diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php
index 6b8707d158a9..1e59805c9bc6 100644
--- a/app/Repositories/UserRepository.php
+++ b/app/Repositories/UserRepository.php
@@ -39,7 +39,7 @@ class UserRepository extends BaseRepository
* @param bool $unset_company_user
* @return \App\Models\User user Object
*/
- public function save(array $data, User $user, $unset_company_user = false)
+ public function save(array $data, User $user, $unset_company_user = false, $is_migrating = false)
{
$details = $data;
@@ -71,7 +71,7 @@ class UserRepository extends BaseRepository
$user->password = Hash::make($data['password']);
}
- if (! $user->confirmation_code) {
+ if (! $user->confirmation_code && !$is_migrating) {
$user->confirmation_code = $this->createDbHash($company->db);
}
diff --git a/app/Services/ClientPortal/InstantPayment.php b/app/Services/ClientPortal/InstantPayment.php
index 2e5feffd85ea..284e79d93a24 100644
--- a/app/Services/ClientPortal/InstantPayment.php
+++ b/app/Services/ClientPortal/InstantPayment.php
@@ -190,7 +190,7 @@ class InstantPayment
/* Schedule a job to check the gateway fees for this invoice*/
if (Ninja::isHosted()) {
- CheckGatewayFee::dispatch($first_invoice->id, $client->company->db)->delay(600);
+ CheckGatewayFee::dispatch($first_invoice->id, $client->company->db)->delay(800);
}
if ($gateway) {
diff --git a/app/Services/Invoice/HandleRestore.php b/app/Services/Invoice/HandleRestore.php
index 18502189f485..4dc9621f4acf 100644
--- a/app/Services/Invoice/HandleRestore.php
+++ b/app/Services/Invoice/HandleRestore.php
@@ -44,6 +44,7 @@ class HandleRestore extends AbstractService
//cannot restore an invoice with a deleted payment
foreach ($this->invoice->payments as $payment) {
if (($this->invoice->paid_to_date == 0) && $payment->is_deleted) {
+ $this->invoice->delete(); //set it back to deleted so that it can be restored from repository
return $this->invoice;
}
}
diff --git a/app/Services/Pdf/PdfBuilder.php b/app/Services/Pdf/PdfBuilder.php
index 78d8d38fb2a9..0e55f97433f7 100644
--- a/app/Services/Pdf/PdfBuilder.php
+++ b/app/Services/Pdf/PdfBuilder.php
@@ -102,7 +102,12 @@ class PdfBuilder
$this->document = $document;
- // $this->xpath = new DOMXPath($document);
+ return $this;
+ }
+
+ public function setDocument($document): self
+ {
+ $this->document = $document;
return $this;
}
@@ -131,6 +136,13 @@ class PdfBuilder
return $this;
}
+ public function setSections($sections): self
+ {
+ $this->sections = $sections;
+
+ return $this;
+ }
+
/**
* Generates delivery note sections
*
@@ -1641,6 +1653,7 @@ class PdfBuilder
public function updateVariables()
{
+
$html = strtr($this->getCompiledHTML(), $this->service->html_variables['labels']);
$html = strtr($html, $this->service->html_variables['values']);
diff --git a/app/Transformers/AccountTransformer.php b/app/Transformers/AccountTransformer.php
index 6d433715c40a..3581ba530ada 100644
--- a/app/Transformers/AccountTransformer.php
+++ b/app/Transformers/AccountTransformer.php
@@ -61,7 +61,7 @@ class AccountTransformer extends EntityTransformer
'plan_paid' => (string) $account->plan_paid,
'plan_expires' => (string) $account->plan_expires,
'user_agent' => (string) $account->user_agent,
- 'payment_id' => (string) $account->payment_id,
+ 'payment_id' => (string) $this->encodePrimaryKey($account->payment_id),
'trial_started' => (string) $account->trial_started,
'trial_plan' => (string) $account->trial_plan,
'plan_price' => (float) $account->plan_price,
diff --git a/app/Utils/Helpers.php b/app/Utils/Helpers.php
index c3c9ad8a10ba..6efc82126297 100644
--- a/app/Utils/Helpers.php
+++ b/app/Utils/Helpers.php
@@ -56,8 +56,35 @@ class Helpers
public function formatCustomFieldValue($custom_fields, $field, $value, $entity = null): ?string
{
$custom_field = '';
+ $quote_or_credit_field = false;
- if ($custom_fields && property_exists($custom_fields, $field)) {
+ if($custom_fields && stripos($field, 'quote') !== false && property_exists($custom_fields, $field)) {
+ $custom_field = $custom_fields->{$field};
+ $custom_field_parts = explode('|', $custom_field);
+
+ if (count($custom_field_parts) >= 2) {
+ $custom_field = $custom_field_parts[1];
+ }
+
+ $quote_or_credit_field = true;
+
+ }elseif($custom_fields && stripos($field, 'credit') !== false && property_exists($custom_fields, $field)) {
+ $custom_field = $custom_fields->{$field};
+ $custom_field_parts = explode('|', $custom_field);
+
+ if (count($custom_field_parts) >= 2) {
+ $custom_field = $custom_field_parts[1];
+ }
+
+ $quote_or_credit_field = true;
+
+ }elseif($custom_fields && stripos($field, 'credit') !== false) {
+ $field = str_replace("credit", "invoice", $field);
+ }elseif($custom_fields && stripos($field, 'quote') !== false) {
+ $field = str_replace("quote", "invoice", $field);
+ }
+
+ if (!$quote_or_credit_field && $custom_fields && property_exists($custom_fields, $field)) {
$custom_field = $custom_fields->{$field};
$custom_field_parts = explode('|', $custom_field);
@@ -90,6 +117,17 @@ class Helpers
*/
public function makeCustomField($custom_fields, $field): string
{
+
+ if ($custom_fields && property_exists($custom_fields, $field)) {
+ $custom_field = $custom_fields->{$field};
+
+ $custom_field_parts = explode('|', $custom_field);
+
+ return $custom_field_parts[0];
+ }
+
+ $field = str_replace(["quote","credit"], ["invoice", "invoice"], $field);
+
if ($custom_fields && property_exists($custom_fields, $field)) {
$custom_field = $custom_fields->{$field};
diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php
index 7bc3c0acec9d..27451e68d1f6 100644
--- a/app/Utils/HtmlEngine.php
+++ b/app/Utils/HtmlEngine.php
@@ -222,10 +222,10 @@ class HtmlEngine
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_quote')];
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->client->date_format(), $this->client->locale()) ?: ' ', 'label' => ctrans('texts.quote_date')];
- $data['$quote.custom1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice1', $this->entity->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice1')];
- $data['$quote.custom2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice2', $this->entity->custom_value2, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice2')];
- $data['$quote.custom3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice3', $this->entity->custom_value3, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice3')];
- $data['$quote.custom4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice4', $this->entity->custom_value4, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice4')];
+ $data['$quote.custom1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'quote1', $this->entity->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'quote1')];
+ $data['$quote.custom2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'quote2', $this->entity->custom_value2, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'quote2')];
+ $data['$quote.custom3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'quote3', $this->entity->custom_value3, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'quote3')];
+ $data['$quote.custom4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'quote4', $this->entity->custom_value4, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'quote4')];
$data['$custom1'] = &$data['$quote.custom1'];
$data['$custom2'] = &$data['$quote.custom2'];
@@ -266,10 +266,10 @@ class HtmlEngine
// $data['$view_link'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_credit')];
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->client->date_format(), $this->client->locale()) ?: ' ', 'label' => ctrans('texts.credit_date')];
- $data['$credit.custom1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit1', $this->entity->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice1')];
- $data['$credit.custom2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit2', $this->entity->custom_value2, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice2')];
- $data['$credit.custom3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit3', $this->entity->custom_value3, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice3')];
- $data['$credit.custom4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit4', $this->entity->custom_value4, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice4')];
+ $data['$credit.custom1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit1', $this->entity->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'credit1')];
+ $data['$credit.custom2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit2', $this->entity->custom_value2, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'credit2')];
+ $data['$credit.custom3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit3', $this->entity->custom_value3, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'credit3')];
+ $data['$credit.custom4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'credit4', $this->entity->custom_value4, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'credit4')];
$data['$custom1'] = &$data['$credit.custom1'];
$data['$custom2'] = &$data['$credit.custom2'];
diff --git a/config/ninja.php b/config/ninja.php
index bf14dd03b055..ec48c4dfa316 100644
--- a/config/ninja.php
+++ b/config/ninja.php
@@ -15,8 +15,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
- 'app_version' => env('APP_VERSION','5.6.17'),
- 'app_tag' => env('APP_TAG','5.6.17'),
+ 'app_version' => env('APP_VERSION','5.6.18'),
+ 'app_tag' => env('APP_TAG','5.6.18'),
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''),
diff --git a/resources/views/portal/ninja2020/components/html-viewer.blade.php b/resources/views/portal/ninja2020/components/html-viewer.blade.php
new file mode 100644
index 000000000000..8b27738e3a54
--- /dev/null
+++ b/resources/views/portal/ninja2020/components/html-viewer.blade.php
@@ -0,0 +1,226 @@
+
+
+
+
+
+
+
+
+ {!! $company_details !!}
+
+
+
+
+
+
+
{!! $entity_details !!}
+
+
+
+
+
+
+
+
+
+ {{ $user_name }}
+
+
+
+
+ {!! $user_details !!}
+
+
+
+
+
+
+
+ @if($products->count() > 0)
+
+
+
+
+ Item
+ Amount
+
+
+
+ @foreach($products as $product)
+
+
+
+
+ {{ $product['line_total'] }}
+
+ @endforeach
+
+
+
+ @endif
+ @if($services->count() > 0)
+
+
+
+
+ Service
+ Amount
+
+
+
+ @foreach($services as $service)
+
+
+
+
+
{{ $service['quantity'] }} × {{ $service['cost'] }}
+
{{ $service['notes'] }}
+
+
+
+ {{ $service['line_total'] }}
+
+ @endforeach
+
+
+
+ @endif
+
+
+
+
+ {{ ctrans('texts.total') }}
+ {{ $amount }}
+
+
+ {{ ctrans('texts.balance') }}
+ {{ $balance }}
+
+
+
+
+
+
+ @if(strlen($entity->public_notes) > 3)
+
+
+
+ {{ ctrans('texts.notes') }}
+
+
+
+
+ {{ strip_tags($entity->public_notes) }}
+
+
+
+ @endif
+
+ @if(strlen($entity->terms) > 3)
+
+
+
+ {{ ctrans('texts.terms') }}
+
+
+
+
+ {{ strip_tags($entity->terms) }}
+
+
+
+ @endif
+
+ @if(strlen($entity->footer) > 3)
+
+
+
+ {{ ctrans('texts.footer') }}
+
+
+
+
+ {{ strip_tags($entity->footer) }}
+
+
+
+
+ @endif
+
+
diff --git a/resources/views/portal/ninja2020/components/livewire/pdf-slot.blade.php b/resources/views/portal/ninja2020/components/livewire/pdf-slot.blade.php
index 05b2ef44b044..553b96d9bf8c 100644
--- a/resources/views/portal/ninja2020/components/livewire/pdf-slot.blade.php
+++ b/resources/views/portal/ninja2020/components/livewire/pdf-slot.blade.php
@@ -1,43 +1,63 @@
-
- @if($pdf)
-
- @else
-
-
-
-
- @endif
+
+
+
+ {{ ctrans('texts.download_pdf') }}
+
+
+
+
+
+ @if($pdf)
+
+ @else
+
+
+
+
+ @endif
+
+
+
+
+@include('portal.ninja2020.components.html-viewer')
+
\ No newline at end of file
diff --git a/resources/views/portal/ninja2020/components/pdf-viewer.blade.php b/resources/views/portal/ninja2020/components/pdf-viewer.blade.php
index bcf438c8de24..75008ab7e424 100644
--- a/resources/views/portal/ninja2020/components/pdf-viewer.blade.php
+++ b/resources/views/portal/ninja2020/components/pdf-viewer.blade.php
@@ -53,32 +53,6 @@
-