mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-11 05:32:39 +01:00
Merge pull request #8903 from turbo124/v5-stable
Adjustment for missing props
This commit is contained in:
commit
cce2fb78f4
@ -1 +1 @@
|
|||||||
5.7.30
|
5.7.33
|
@ -11,16 +11,18 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\DataMapper\CompanySettings;
|
use Faker\Factory;
|
||||||
use App\DataMapper\DefaultSettings;
|
use App\Models\User;
|
||||||
use App\Jobs\Mail\NinjaMailerJob;
|
|
||||||
use App\Jobs\Mail\NinjaMailerObject;
|
|
||||||
use App\Mail\Migration\MaxCompanies;
|
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\User;
|
use App\Mail\TestMailServer;
|
||||||
use Faker\Factory;
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use App\Jobs\Mail\NinjaMailerJob;
|
||||||
|
use App\DataMapper\CompanySettings;
|
||||||
|
use App\DataMapper\DefaultSettings;
|
||||||
|
use App\Jobs\Mail\NinjaMailerObject;
|
||||||
|
use App\Mail\Migration\MaxCompanies;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
|
||||||
class SendTestEmails extends Command
|
class SendTestEmails extends Command
|
||||||
{
|
{
|
||||||
@ -55,39 +57,26 @@ class SendTestEmails extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$faker = Factory::create();
|
|
||||||
|
|
||||||
$account = Account::factory()->create();
|
$to_user = User::first();
|
||||||
|
|
||||||
$user = User::factory()->create([
|
|
||||||
'account_id' => $account->id,
|
|
||||||
'confirmation_code' => '123',
|
|
||||||
'email' => $faker->safeEmail(),
|
|
||||||
'first_name' => 'John',
|
|
||||||
'last_name' => 'Doe',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$company = Company::factory()->create([
|
|
||||||
'account_id' => $account->id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$user->companies()->attach($company->id, [
|
|
||||||
'account_id' => $account->id,
|
|
||||||
'is_owner' => 1,
|
|
||||||
'is_admin' => 1,
|
|
||||||
'is_locked' => 0,
|
|
||||||
'permissions' => '',
|
|
||||||
'notifications' => CompanySettings::notificationDefaults(),
|
|
||||||
//'settings' => DefaultSettings::userSettings(),
|
|
||||||
'settings' => null,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$nmo = new NinjaMailerObject;
|
$nmo = new NinjaMailerObject;
|
||||||
$nmo->mailable = new MaxCompanies($user->account->companies()->first());
|
$nmo->mailable = new TestMailServer('Email Server Works!', config('mail.from.address'));
|
||||||
$nmo->company = $user->account->companies()->first();
|
$nmo->company = $to_user->account->companies()->first();
|
||||||
$nmo->settings = $user->account->companies()->first()->settings;
|
$nmo->settings = $to_user->account->companies()->first()->settings;
|
||||||
$nmo->to_user = $user;
|
$nmo->to_user = $to_user;
|
||||||
|
|
||||||
(new NinjaMailerJob($nmo))->handle();
|
try {
|
||||||
|
|
||||||
|
Mail::raw("Test Message", function ($message) {
|
||||||
|
$message->to(config('mail.from.address'))
|
||||||
|
->from(config('mail.from.address'), config('mail.from.name'))
|
||||||
|
->subject('Test Email');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
$this->info("Error sending email: " . $e->getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
515
app/DataMapper/Settings/SettingsData.php
Normal file
515
app/DataMapper/Settings/SettingsData.php
Normal file
@ -0,0 +1,515 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
namespace App\DataMapper\Settings;
|
||||||
|
|
||||||
|
class SettingsData
|
||||||
|
{
|
||||||
|
|
||||||
|
public bool $auto_archive_invoice = false; // @implemented
|
||||||
|
|
||||||
|
public string $qr_iban = ''; //@implemented
|
||||||
|
|
||||||
|
public string $besr_id = ''; //@implemented
|
||||||
|
|
||||||
|
public string $lock_invoices = 'off'; // off, when_sent, when_paid //@implemented
|
||||||
|
|
||||||
|
public bool $enable_client_portal_tasks = false; //@ben to implement
|
||||||
|
|
||||||
|
public string $show_all_tasks_client_portal = 'invoiced'; // all, uninvoiced, invoiced
|
||||||
|
|
||||||
|
public bool $enable_client_portal_password = false; //@implemented
|
||||||
|
|
||||||
|
public bool $enable_client_portal = true; //@implemented
|
||||||
|
|
||||||
|
public bool $enable_client_portal_dashboard = false; // @TODO There currently is no dashboard, so this is pending
|
||||||
|
|
||||||
|
public bool $signature_on_pdf = false; //@implemented
|
||||||
|
|
||||||
|
public bool $document_email_attachment = false; //@TODO I assume this is 3rd party attachments on the entity to be included
|
||||||
|
|
||||||
|
public string $portal_design_id = '1'; //? @deprecated
|
||||||
|
|
||||||
|
public string $timezone_id = ''; //@implemented
|
||||||
|
|
||||||
|
public string $date_format_id = ''; //@implemented
|
||||||
|
|
||||||
|
public bool $military_time = false; // @TODO Implemented in Tasks only?
|
||||||
|
|
||||||
|
public string $language_id = ''; //@implemented
|
||||||
|
|
||||||
|
public bool $show_currency_code = false; //@implemented
|
||||||
|
|
||||||
|
public string $company_gateway_ids = ''; //@implemented
|
||||||
|
|
||||||
|
public string $currency_id = '1'; //@implemented
|
||||||
|
|
||||||
|
public string $custom_value1 = ''; //@implemented
|
||||||
|
|
||||||
|
public string $custom_value2 = ''; //@implemented
|
||||||
|
|
||||||
|
public string $custom_value3 = ''; //@implemented
|
||||||
|
|
||||||
|
public string $custom_value4 = ''; //@implemented
|
||||||
|
|
||||||
|
public float $default_task_rate = 0; // @TODO Where do we inject this?
|
||||||
|
|
||||||
|
public string $payment_terms = ''; //@implemented
|
||||||
|
|
||||||
|
public bool $send_reminders = true; //@TODO
|
||||||
|
|
||||||
|
public string $custom_message_dashboard = ''; // @TODO There currently is no dashboard, so this is pending
|
||||||
|
|
||||||
|
public string $custom_message_unpaid_invoice = '';
|
||||||
|
|
||||||
|
public string $custom_message_paid_invoice = '';
|
||||||
|
|
||||||
|
public string $custom_message_unapproved_quote = '';
|
||||||
|
|
||||||
|
public bool $auto_archive_quote = false; //@implemented
|
||||||
|
|
||||||
|
public bool $auto_convert_quote = true; //@implemented
|
||||||
|
|
||||||
|
public bool $auto_email_invoice = true; //@only used for Recurring Invoices, if set to false, we never send?
|
||||||
|
|
||||||
|
public int $entity_send_time = 6;
|
||||||
|
|
||||||
|
public bool $inclusive_taxes = false; //@implemented
|
||||||
|
|
||||||
|
public string $quote_footer = ''; //@implemented
|
||||||
|
|
||||||
|
public object $translations;
|
||||||
|
|
||||||
|
public string $counter_number_applied = 'when_saved'; // when_saved, when_sent //@implemented
|
||||||
|
|
||||||
|
public string $quote_number_applied = 'when_saved'; // when_saved, when_sent //@implemented
|
||||||
|
|
||||||
|
public string $invoice_number_pattern = ''; //@implemented
|
||||||
|
|
||||||
|
public int $invoice_number_counter = 1; //@implemented
|
||||||
|
|
||||||
|
public string $recurring_invoice_number_pattern = ''; //@implemented
|
||||||
|
|
||||||
|
public int $recurring_invoice_number_counter = 1; //@implemented
|
||||||
|
|
||||||
|
public string $quote_number_pattern = ''; //@implemented
|
||||||
|
|
||||||
|
public int $quote_number_counter = 1; //@implemented
|
||||||
|
|
||||||
|
public string $client_number_pattern = ''; //@implemented
|
||||||
|
|
||||||
|
public int $client_number_counter = 1; //@implemented
|
||||||
|
|
||||||
|
public string $credit_number_pattern = ''; //@implemented
|
||||||
|
|
||||||
|
public int $credit_number_counter = 1; //@implemented
|
||||||
|
|
||||||
|
public string $task_number_pattern = ''; //@implemented
|
||||||
|
|
||||||
|
public int $task_number_counter = 1; //@implemented
|
||||||
|
|
||||||
|
public string $expense_number_pattern = ''; //@implemented
|
||||||
|
|
||||||
|
public int $expense_number_counter = 1; //@implemented
|
||||||
|
|
||||||
|
public string $recurring_expense_number_pattern = '';
|
||||||
|
|
||||||
|
public int $recurring_expense_number_counter = 1;
|
||||||
|
|
||||||
|
public string $recurring_quote_number_pattern = '';
|
||||||
|
|
||||||
|
public int $recurring_quote_number_counter = 1;
|
||||||
|
|
||||||
|
public string $vendor_number_pattern = ''; //@implemented
|
||||||
|
|
||||||
|
public int $vendor_number_counter = 1; //@implemented
|
||||||
|
|
||||||
|
public string $ticket_number_pattern = ''; //@implemented
|
||||||
|
|
||||||
|
public int $ticket_number_counter = 1; //@implemented
|
||||||
|
|
||||||
|
public string $payment_number_pattern = ''; //@implemented
|
||||||
|
|
||||||
|
public int $payment_number_counter = 1; //@implemented
|
||||||
|
|
||||||
|
public string $project_number_pattern = ''; //@implemented
|
||||||
|
|
||||||
|
public int $project_number_counter = 1; //@implemented
|
||||||
|
|
||||||
|
public string $purchase_order_number_pattern = ''; //@implemented
|
||||||
|
|
||||||
|
public int $purchase_order_number_counter = 1; //@implemented
|
||||||
|
|
||||||
|
public bool $shared_invoice_quote_counter = false; //@implemented
|
||||||
|
|
||||||
|
public bool $shared_invoice_credit_counter = false; //@implemented
|
||||||
|
|
||||||
|
public string $recurring_number_prefix = ''; //@implemented
|
||||||
|
|
||||||
|
public string $reset_counter_frequency_id = '0'; //@implemented
|
||||||
|
|
||||||
|
public string $reset_counter_date = ''; //@implemented
|
||||||
|
|
||||||
|
public int $counter_padding = 4; //@implemented
|
||||||
|
|
||||||
|
public string $auto_bill = 'off'; // off, always, opt-in, opt-out //@implemented
|
||||||
|
|
||||||
|
public string $auto_bill_date = 'on_due_date'; // on_due_date, on_send_date //@implemented
|
||||||
|
|
||||||
|
public string $invoice_terms = ''; //@implemented
|
||||||
|
|
||||||
|
public string $quote_terms = ''; //@implemented
|
||||||
|
|
||||||
|
public int $invoice_taxes = 0; // ? used in AP only?
|
||||||
|
|
||||||
|
public string $invoice_design_id = 'Wpmbk5ezJn'; //@implemented
|
||||||
|
|
||||||
|
public string $quote_design_id = 'Wpmbk5ezJn'; //@implemented
|
||||||
|
|
||||||
|
public string $credit_design_id = 'Wpmbk5ezJn'; //@implemented
|
||||||
|
|
||||||
|
public string $purchase_order_design_id = 'Wpmbk5ezJn';
|
||||||
|
|
||||||
|
public string $purchase_order_footer = ''; //@implemented
|
||||||
|
|
||||||
|
public string $purchase_order_terms = ''; //@implemented
|
||||||
|
|
||||||
|
public string $purchase_order_public_notes = ''; //@implemented
|
||||||
|
|
||||||
|
public bool $require_purchase_order_signature = false; //@TODO ben to confirm
|
||||||
|
|
||||||
|
public string $invoice_footer = ''; //@implemented
|
||||||
|
|
||||||
|
public string $credit_footer = ''; //@implemented
|
||||||
|
|
||||||
|
public string $credit_terms = ''; //@implemented
|
||||||
|
|
||||||
|
public string $invoice_labels = ''; //@TODO used in AP only?
|
||||||
|
|
||||||
|
public string $tax_name1 = ''; //@TODO where do we use this?
|
||||||
|
|
||||||
|
public float $tax_rate1 = 0; //@TODO where do we use this?
|
||||||
|
|
||||||
|
public string $tax_name2 = ''; //@TODO where do we use this?
|
||||||
|
|
||||||
|
public float $tax_rate2 = 0; //@TODO where do we use this?
|
||||||
|
|
||||||
|
public string $tax_name3 = ''; //@TODO where do we use this?
|
||||||
|
|
||||||
|
public float $tax_rate3 = 0; //@TODO where do we use this?
|
||||||
|
|
||||||
|
public string $payment_type_id = '0'; //@TODO where do we use this?
|
||||||
|
|
||||||
|
public string $valid_until = ''; //@implemented
|
||||||
|
|
||||||
|
public bool $show_accept_invoice_terms = false; //@TODO ben to confirm
|
||||||
|
|
||||||
|
public bool $show_accept_quote_terms = false; //@TODO ben to confirm
|
||||||
|
|
||||||
|
public string $email_sending_method = 'default'; // enum 'default', 'gmail', 'office365', 'client_postmark', 'client_mailgun' //@implemented
|
||||||
|
|
||||||
|
public string $gmail_sending_user_id = '0'; //@implemented
|
||||||
|
|
||||||
|
public string $reply_to_email = ''; //@implemented
|
||||||
|
|
||||||
|
public string $reply_to_name = ''; //@implemented
|
||||||
|
|
||||||
|
public string $bcc_email = ''; //@TODO
|
||||||
|
|
||||||
|
public bool $pdf_email_attachment = false; //@implemented
|
||||||
|
|
||||||
|
public bool $ubl_email_attachment = false; //@implemented
|
||||||
|
|
||||||
|
public string $email_style = 'light'; // plain, light, dark, custom //@implemented
|
||||||
|
|
||||||
|
public string $email_style_custom = ''; // the template itself //@implemented
|
||||||
|
|
||||||
|
public string $email_subject_invoice = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_subject_quote = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_subject_credit = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_subject_payment = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_subject_payment_partial = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_subject_statement = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_subject_purchase_order = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_template_purchase_order = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_template_invoice = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_template_credit = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_template_quote = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_template_payment = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_template_payment_partial = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_template_statement = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_subject_reminder1 = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_subject_reminder2 = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_subject_reminder3 = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_subject_reminder_endless = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_template_reminder1 = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_template_reminder2 = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_template_reminder3 = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_template_reminder_endless = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email_signature = ''; //@implemented
|
||||||
|
|
||||||
|
public bool $enable_email_markup = true; //@TODO -
|
||||||
|
|
||||||
|
public string $email_subject_custom1 = ''; //@TODO
|
||||||
|
|
||||||
|
public string $email_subject_custom2 = ''; //@TODO
|
||||||
|
|
||||||
|
public string $email_subject_custom3 = ''; //@TODO
|
||||||
|
|
||||||
|
public string $email_template_custom1 = ''; //@TODO
|
||||||
|
|
||||||
|
public string $email_template_custom2 = ''; //@TODO
|
||||||
|
|
||||||
|
public string $email_template_custom3 = ''; //@TODO
|
||||||
|
|
||||||
|
public bool $enable_reminder1 = false; //@implmemented
|
||||||
|
|
||||||
|
public bool $enable_reminder2 = false; //@implmemented
|
||||||
|
|
||||||
|
public bool $enable_reminder3 = false; //@implmemented
|
||||||
|
|
||||||
|
public bool $enable_reminder_endless = false; //@implmemented
|
||||||
|
|
||||||
|
public int $num_days_reminder1 = 0; //@implmemented
|
||||||
|
|
||||||
|
public int $num_days_reminder2 = 0; //@implmemented
|
||||||
|
|
||||||
|
public int $num_days_reminder3 = 0; //@implmemented
|
||||||
|
|
||||||
|
public string $schedule_reminder1 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
|
||||||
|
|
||||||
|
public string $schedule_reminder2 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
|
||||||
|
|
||||||
|
public string $schedule_reminder3 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
|
||||||
|
|
||||||
|
public int $reminder_send_time = 0; // number of seconds from UTC +0 to send reminders @TODO
|
||||||
|
|
||||||
|
public float $late_fee_amount1 = 0; //@implemented
|
||||||
|
|
||||||
|
public float $late_fee_amount2 = 0; //@implemented
|
||||||
|
|
||||||
|
public float $late_fee_amount3 = 0; //@implemented
|
||||||
|
|
||||||
|
public float $late_fee_percent1 = 0; //@implemented
|
||||||
|
|
||||||
|
public float $late_fee_percent2 = 0; //@implemented
|
||||||
|
|
||||||
|
public float $late_fee_percent3 = 0; //@implemented
|
||||||
|
|
||||||
|
public string $endless_reminder_frequency_id = '0'; //@implemented
|
||||||
|
|
||||||
|
public float $late_fee_endless_amount = 0; //@implemented
|
||||||
|
|
||||||
|
public float $late_fee_endless_percent = 0; //@implemented
|
||||||
|
|
||||||
|
public bool $client_online_payment_notification = true; //@todo implement in notifications check this bool prior to sending payment notification to client
|
||||||
|
|
||||||
|
public bool $client_manual_payment_notification = true; //@todo implement in notifications check this bool prior to sending manual payment notification to client
|
||||||
|
|
||||||
|
public string $name = ''; //@implemented
|
||||||
|
|
||||||
|
public string $company_logo = ''; //@implemented
|
||||||
|
|
||||||
|
public string $website = ''; //@implemented
|
||||||
|
|
||||||
|
public string $address1 = ''; //@implemented
|
||||||
|
|
||||||
|
public string $address2 = ''; //@implemented
|
||||||
|
|
||||||
|
public string $city = ''; //@implemented
|
||||||
|
|
||||||
|
public string $state = ''; //@implemented
|
||||||
|
|
||||||
|
public string $postal_code = ''; //@implemented
|
||||||
|
|
||||||
|
public string $phone = ''; //@implemented
|
||||||
|
|
||||||
|
public string $email = ''; //@implemented
|
||||||
|
|
||||||
|
public string $country_id; //@implemented
|
||||||
|
|
||||||
|
public string $vat_number = ''; //@implemented
|
||||||
|
|
||||||
|
public string $id_number = ''; //@implemented
|
||||||
|
|
||||||
|
public string $page_size = 'A4'; // Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A4, A5, A6
|
||||||
|
|
||||||
|
public string $page_layout = 'portrait';
|
||||||
|
|
||||||
|
public int $font_size = 16; //@implemented
|
||||||
|
|
||||||
|
public string $primary_font = 'Roboto';
|
||||||
|
|
||||||
|
public string $secondary_font = 'Roboto';
|
||||||
|
|
||||||
|
public string $primary_color = '#298AAB';
|
||||||
|
|
||||||
|
public string $secondary_color = '#7081e0';
|
||||||
|
|
||||||
|
public bool $page_numbering = false;
|
||||||
|
|
||||||
|
public string $page_numbering_alignment = 'C'; // C, R, L
|
||||||
|
|
||||||
|
public bool $hide_paid_to_date = false; //@TODO where?
|
||||||
|
|
||||||
|
public bool $embed_documents = false; //@TODO where?
|
||||||
|
|
||||||
|
public bool $all_pages_header = false; //@deprecated 31-05-2021
|
||||||
|
|
||||||
|
public bool $all_pages_footer = false; //@deprecated 31-05-2021
|
||||||
|
|
||||||
|
public string $pdf_variables = ''; //@implemented
|
||||||
|
|
||||||
|
public string $portal_custom_head = ''; //@TODO @BEN
|
||||||
|
|
||||||
|
public string $portal_custom_css = ''; //@TODO @BEN
|
||||||
|
|
||||||
|
public string $portal_custom_footer = ''; //@TODO @BEN
|
||||||
|
|
||||||
|
public string $portal_custom_js = ''; //@TODO @BEN
|
||||||
|
|
||||||
|
public bool $client_can_register = false; //@deprecated 04/06/2021
|
||||||
|
|
||||||
|
public string $client_portal_terms = ''; //@TODO @BEN
|
||||||
|
|
||||||
|
public string $client_portal_privacy_policy = ''; //@TODO @BEN
|
||||||
|
|
||||||
|
public bool $client_portal_enable_uploads = false; //@implemented
|
||||||
|
|
||||||
|
public bool $client_portal_allow_under_payment = false; //@implemented
|
||||||
|
|
||||||
|
public float $client_portal_under_payment_minimum = 0; //@implemented
|
||||||
|
|
||||||
|
public bool $client_portal_allow_over_payment = false; //@implemented
|
||||||
|
|
||||||
|
public string $use_credits_payment = 'off'; // always, option, off //@implemented
|
||||||
|
|
||||||
|
public bool $hide_empty_columns_on_pdf = false;
|
||||||
|
|
||||||
|
public string $email_from_name = '';
|
||||||
|
|
||||||
|
public bool $auto_archive_invoice_cancelled = false;
|
||||||
|
|
||||||
|
public bool $vendor_portal_enable_uploads = false;
|
||||||
|
|
||||||
|
public bool $send_email_on_mark_paid = false;
|
||||||
|
|
||||||
|
public string $postmark_secret = '';
|
||||||
|
|
||||||
|
public string $custom_sending_email = '';
|
||||||
|
|
||||||
|
public string $mailgun_secret = '';
|
||||||
|
|
||||||
|
public string $mailgun_domain = '';
|
||||||
|
|
||||||
|
public string $mailgun_endpoint = 'api.mailgun.net'; // api.eu.mailgun.net
|
||||||
|
|
||||||
|
public bool $auto_bill_standard_invoices = false;
|
||||||
|
|
||||||
|
public string $email_alignment = 'center'; // center, left, right
|
||||||
|
|
||||||
|
public bool $show_email_footer = true;
|
||||||
|
|
||||||
|
public string $company_logo_size = '';
|
||||||
|
|
||||||
|
public bool $show_paid_stamp = false;
|
||||||
|
|
||||||
|
public bool $show_shipping_address = false;
|
||||||
|
|
||||||
|
public bool $accept_client_input_quote_approval = false;
|
||||||
|
|
||||||
|
public bool $allow_billable_task_items = true;
|
||||||
|
|
||||||
|
public bool $show_task_item_description = false;
|
||||||
|
|
||||||
|
public bool $client_initiated_payments = false;
|
||||||
|
|
||||||
|
public float $client_initiated_payments_minimum = 0;
|
||||||
|
|
||||||
|
public bool $sync_invoice_quote_columns = true;
|
||||||
|
|
||||||
|
public string $e_invoice_type = 'EN16931';
|
||||||
|
|
||||||
|
public string $default_expense_payment_type_id = '0';
|
||||||
|
|
||||||
|
public bool $enable_e_invoice = false;
|
||||||
|
|
||||||
|
public string $classification = '';
|
||||||
|
|
||||||
|
private mixed $object;
|
||||||
|
|
||||||
|
public function cast(mixed $object)
|
||||||
|
{
|
||||||
|
if(is_array($object))
|
||||||
|
$object = (object)$object;
|
||||||
|
|
||||||
|
if (is_object($object)) {
|
||||||
|
foreach ($object as $key => $value) {
|
||||||
|
|
||||||
|
try{
|
||||||
|
settype($object->{$key}, gettype($this->{$key}));
|
||||||
|
}
|
||||||
|
catch(\Exception | \Error | \Throwable $e){
|
||||||
|
|
||||||
|
if(property_exists($this, $key))
|
||||||
|
$object->{$key} = $this->{$key};
|
||||||
|
else
|
||||||
|
unset($object->{$key});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(!property_exists($this, $key)) {
|
||||||
|
// unset($object->{$key});
|
||||||
|
// }
|
||||||
|
// elseif(is_array($object->{$key}) && gettype($this->{$key} != 'array')){
|
||||||
|
// $object->{$key} = $this->{$key};
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// settype($object->{$key}, gettype($this->{$key}));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->object = $object;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toObject(): object
|
||||||
|
{
|
||||||
|
return (object)$this->object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return (array)$this->object;
|
||||||
|
}
|
||||||
|
}
|
@ -62,7 +62,7 @@ class Rule extends BaseRule implements RuleInterface
|
|||||||
public function taxByType($item): self
|
public function taxByType($item): self
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($this->client->is_tax_exempt) {
|
if ($this->client->is_tax_exempt || !property_exists($item, 'tax_id')) {
|
||||||
return $this->taxExempt($item);
|
return $this->taxExempt($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ class BaseRule implements RuleInterface
|
|||||||
public function tax($item = null): self
|
public function tax($item = null): self
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($this->client->is_tax_exempt) {
|
if ($this->client->is_tax_exempt || !property_exists($item, 'tax_id')) {
|
||||||
|
|
||||||
return $this->taxExempt($item);
|
return $this->taxExempt($item);
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ class Rule extends BaseRule implements RuleInterface
|
|||||||
public function taxByType($item): self
|
public function taxByType($item): self
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($this->client->is_tax_exempt) {
|
if ($this->client->is_tax_exempt || !property_exists($item, 'tax_id')) {
|
||||||
return $this->taxExempt($item);
|
return $this->taxExempt($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ class BaseExport
|
|||||||
|
|
||||||
protected array $client_report_keys = [
|
protected array $client_report_keys = [
|
||||||
"name" => "client.name",
|
"name" => "client.name",
|
||||||
|
"number" => "client.number",
|
||||||
"user" => "client.user",
|
"user" => "client.user",
|
||||||
"assigned_user" => "client.assigned_user",
|
"assigned_user" => "client.assigned_user",
|
||||||
"balance" => "client.balance",
|
"balance" => "client.balance",
|
||||||
@ -168,6 +169,7 @@ class BaseExport
|
|||||||
'tax_rate1' => 'invoice.tax_rate1',
|
'tax_rate1' => 'invoice.tax_rate1',
|
||||||
'tax_rate2' => 'invoice.tax_rate2',
|
'tax_rate2' => 'invoice.tax_rate2',
|
||||||
'tax_rate3' => 'invoice.tax_rate3',
|
'tax_rate3' => 'invoice.tax_rate3',
|
||||||
|
'recurring_invoice' => 'invoice.recurring_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected array $recurring_invoice_report_keys = [
|
protected array $recurring_invoice_report_keys = [
|
||||||
@ -230,7 +232,7 @@ class BaseExport
|
|||||||
'po_number' => 'purchase_order.po_number',
|
'po_number' => 'purchase_order.po_number',
|
||||||
'private_notes' => 'purchase_order.private_notes',
|
'private_notes' => 'purchase_order.private_notes',
|
||||||
'public_notes' => 'purchase_order.public_notes',
|
'public_notes' => 'purchase_order.public_notes',
|
||||||
'status' => 'purchase_order.status_id',
|
'status' => 'purchase_order.status',
|
||||||
'tax_name1' => 'purchase_order.tax_name1',
|
'tax_name1' => 'purchase_order.tax_name1',
|
||||||
'tax_name2' => 'purchase_order.tax_name2',
|
'tax_name2' => 'purchase_order.tax_name2',
|
||||||
'tax_name3' => 'purchase_order.tax_name3',
|
'tax_name3' => 'purchase_order.tax_name3',
|
||||||
@ -377,6 +379,7 @@ class BaseExport
|
|||||||
"custom_value4" => "payment.custom_value4",
|
"custom_value4" => "payment.custom_value4",
|
||||||
"user" => "payment.user_id",
|
"user" => "payment.user_id",
|
||||||
"assigned_user" => "payment.assigned_user_id",
|
"assigned_user" => "payment.assigned_user_id",
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
protected array $expense_report_keys = [
|
protected array $expense_report_keys = [
|
||||||
@ -429,6 +432,14 @@ class BaseExport
|
|||||||
'project' => 'task.project_id',
|
'project' => 'task.project_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected array $forced_client_fields = [
|
||||||
|
"client.name",
|
||||||
|
];
|
||||||
|
|
||||||
|
protected array $forced_vendor_fields = [
|
||||||
|
"vendor.name",
|
||||||
|
];
|
||||||
|
|
||||||
protected function filterByClients($query)
|
protected function filterByClients($query)
|
||||||
{
|
{
|
||||||
if (isset($this->input['client_id']) && $this->input['client_id'] != 'all') {
|
if (isset($this->input['client_id']) && $this->input['client_id'] != 'all') {
|
||||||
@ -1144,9 +1155,9 @@ class BaseExport
|
|||||||
$clean_row[$key]['entity'] = $report_keys[0];
|
$clean_row[$key]['entity'] = $report_keys[0];
|
||||||
$clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0];
|
$clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0];
|
||||||
$clean_row[$key]['hashed_id'] = $report_keys[0] == $entity ? null : $resource->{$report_keys[0]}->hashed_id ?? null;
|
$clean_row[$key]['hashed_id'] = $report_keys[0] == $entity ? null : $resource->{$report_keys[0]}->hashed_id ?? null;
|
||||||
$clean_row[$key]['value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]];
|
$clean_row[$key]['value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$value];
|
||||||
$clean_row[$key]['identifier'] = $value;
|
$clean_row[$key]['identifier'] = $value;
|
||||||
$clean_row[$key]['display_value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$report_keys[1]];
|
$clean_row[$key]['display_value'] = isset($row[$column_key]) ? $row[$column_key] : $row[$value];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ class ClientExport extends BaseExport
|
|||||||
$clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0];
|
$clean_row[$key]['id'] = $report_keys[1] ?? $report_keys[0];
|
||||||
$clean_row[$key]['hashed_id'] = $report_keys[0] == 'client' ? null : $resource->{$report_keys[0]}->hashed_id ?? null;
|
$clean_row[$key]['hashed_id'] = $report_keys[0] == 'client' ? null : $resource->{$report_keys[0]}->hashed_id ?? null;
|
||||||
$clean_row[$key]['value'] = $row[$column_key];
|
$clean_row[$key]['value'] = $row[$column_key];
|
||||||
$clean_row[$key]['identifier'] = $key;
|
$clean_row[$key]['identifier'] = $value;
|
||||||
|
|
||||||
if(in_array($clean_row[$key]['id'], ['paid_to_date', 'balance', 'credit_balance','payment_balance']))
|
if(in_array($clean_row[$key]['id'], ['paid_to_date', 'balance', 'credit_balance','payment_balance']))
|
||||||
$clean_row[$key]['display_value'] = Number::formatMoney($row[$column_key], $resource);
|
$clean_row[$key]['display_value'] = Number::formatMoney($row[$column_key], $resource);
|
||||||
|
@ -93,6 +93,8 @@ class CreditExport extends BaseExport
|
|||||||
$this->input['report_keys'] = array_values($this->credit_report_keys);
|
$this->input['report_keys'] = array_values($this->credit_report_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
|
||||||
|
|
||||||
$query = Credit::query()
|
$query = Credit::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->with('client')
|
->with('client')
|
||||||
|
@ -50,6 +50,8 @@ class InvoiceExport extends BaseExport
|
|||||||
$this->input['report_keys'] = array_values($this->invoice_report_keys);
|
$this->input['report_keys'] = array_values($this->invoice_report_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
|
||||||
|
|
||||||
$query = Invoice::query()
|
$query = Invoice::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->with('client')
|
->with('client')
|
||||||
@ -142,6 +144,11 @@ class InvoiceExport extends BaseExport
|
|||||||
if (in_array('invoice.status', $this->input['report_keys'])) {
|
if (in_array('invoice.status', $this->input['report_keys'])) {
|
||||||
$entity['invoice.status'] = $invoice->stringStatus($invoice->status_id);
|
$entity['invoice.status'] = $invoice->stringStatus($invoice->status_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in_array('invoice.recurring_id', $this->input['report_keys'])) {
|
||||||
|
$entity['invoice.recurring_id'] = $invoice->recurring_invoice->number ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,8 @@ class InvoiceItemExport extends BaseExport
|
|||||||
$this->input['report_keys'] = array_values($this->mergeItemsKeys('invoice_report_keys'));
|
$this->input['report_keys'] = array_values($this->mergeItemsKeys('invoice_report_keys'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
|
||||||
|
|
||||||
$query = Invoice::query()
|
$query = Invoice::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->with('client')
|
->with('client')
|
||||||
@ -135,16 +137,16 @@ class InvoiceItemExport extends BaseExport
|
|||||||
|
|
||||||
if (str_contains($key, "item.")) {
|
if (str_contains($key, "item.")) {
|
||||||
|
|
||||||
$key = str_replace("item.", "", $key);
|
$tmp_key = str_replace("item.", "", $key);
|
||||||
|
|
||||||
if($key == 'type_id')
|
if($tmp_key == 'type_id')
|
||||||
$key = 'type';
|
$tmp_key = 'type';
|
||||||
|
|
||||||
if($key == 'tax_id')
|
if($tmp_key == 'tax_id')
|
||||||
$key = 'tax_category';
|
$tmp_key = 'tax_category';
|
||||||
|
|
||||||
if (property_exists($item, $key)) {
|
if (property_exists($item, $tmp_key)) {
|
||||||
$item_array[$key] = $item->{$key};
|
$item_array[$key] = $item->{$tmp_key};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$item_array[$key] = '';
|
$item_array[$key] = '';
|
||||||
@ -154,6 +156,8 @@ class InvoiceItemExport extends BaseExport
|
|||||||
|
|
||||||
$transformed_items = array_merge($transformed_invoice, $item_array);
|
$transformed_items = array_merge($transformed_invoice, $item_array);
|
||||||
$entity = $this->decorateAdvancedFields($invoice, $transformed_items);
|
$entity = $this->decorateAdvancedFields($invoice, $transformed_items);
|
||||||
|
|
||||||
|
$entity = array_merge(array_flip(array_values($this->input['report_keys'])), $entity);
|
||||||
|
|
||||||
$this->storage_array[] = $entity;
|
$this->storage_array[] = $entity;
|
||||||
|
|
||||||
@ -200,6 +204,27 @@ class InvoiceItemExport extends BaseExport
|
|||||||
$entity['tax_category'] = $invoice->taxTypeString($entity['tax_category']);
|
$entity['tax_category'] = $invoice->taxTypeString($entity['tax_category']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in_array('invoice.country_id', $this->input['report_keys'])) {
|
||||||
|
$entity['invoice.country_id'] = $invoice->client->country ? ctrans("texts.country_{$invoice->client->country->name}") : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array('invoice.currency_id', $this->input['report_keys'])) {
|
||||||
|
$entity['invoice.currency_id'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array('invoice.client_id', $this->input['report_keys'])) {
|
||||||
|
$entity['invoice.client_id'] = $invoice->client->present()->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array('invoice.status', $this->input['report_keys'])) {
|
||||||
|
$entity['invoice.status'] = $invoice->stringStatus($invoice->status_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array('invoice.recurring_id', $this->input['report_keys'])) {
|
||||||
|
$entity['invoice.recurring_id'] = $invoice->recurring_invoice->number ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,8 @@ class PaymentExport extends BaseExport
|
|||||||
$this->input['report_keys'] = array_values($this->payment_report_keys);
|
$this->input['report_keys'] = array_values($this->payment_report_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
|
||||||
|
|
||||||
$query = Payment::query()
|
$query = Payment::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->where('company_id', $this->company->id)
|
->where('company_id', $this->company->id)
|
||||||
@ -69,6 +71,8 @@ class PaymentExport extends BaseExport
|
|||||||
return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
|
return ['identifier' => $key, 'display_value' => $headerdisplay[$value]];
|
||||||
})->toArray();
|
})->toArray();
|
||||||
|
|
||||||
|
nlog($header);
|
||||||
|
|
||||||
$report = $query->cursor()
|
$report = $query->cursor()
|
||||||
->map(function ($resource) {
|
->map(function ($resource) {
|
||||||
$row = $this->buildRow($resource);
|
$row = $this->buildRow($resource);
|
||||||
|
@ -54,7 +54,7 @@ class PurchaseOrderExport extends BaseExport
|
|||||||
'po_number' => 'purchase_order.po_number',
|
'po_number' => 'purchase_order.po_number',
|
||||||
'private_notes' => 'purchase_order.private_notes',
|
'private_notes' => 'purchase_order.private_notes',
|
||||||
'public_notes' => 'purchase_order.public_notes',
|
'public_notes' => 'purchase_order.public_notes',
|
||||||
'status' => 'purchase_order.status_id',
|
'status' => 'purchase_order.status',
|
||||||
'tax_name1' => 'purchase_order.tax_name1',
|
'tax_name1' => 'purchase_order.tax_name1',
|
||||||
'tax_name2' => 'purchase_order.tax_name2',
|
'tax_name2' => 'purchase_order.tax_name2',
|
||||||
'tax_name3' => 'purchase_order.tax_name3',
|
'tax_name3' => 'purchase_order.tax_name3',
|
||||||
@ -95,6 +95,9 @@ class PurchaseOrderExport extends BaseExport
|
|||||||
if (count($this->input['report_keys']) == 0) {
|
if (count($this->input['report_keys']) == 0) {
|
||||||
$this->input['report_keys'] = array_values($this->purchase_order_report_keys);
|
$this->input['report_keys'] = array_values($this->purchase_order_report_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_vendor_fields, $this->input['report_keys']));
|
||||||
|
|
||||||
$query = PurchaseOrder::query()
|
$query = PurchaseOrder::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->with('vendor')
|
->with('vendor')
|
||||||
@ -181,8 +184,8 @@ class PurchaseOrderExport extends BaseExport
|
|||||||
$entity['vendor'] = $purchase_order->vendor->present()->name();
|
$entity['vendor'] = $purchase_order->vendor->present()->name();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array('status_id', $this->input['report_keys'])) {
|
if (in_array('purchase_order.status', $this->input['report_keys'])) {
|
||||||
$entity['status'] = $purchase_order->stringStatus($purchase_order->status_id);
|
$entity['purchase_order.status'] = $purchase_order->stringStatus($purchase_order->status_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
|
@ -55,6 +55,8 @@ class PurchaseOrderItemExport extends BaseExport
|
|||||||
$this->input['report_keys'] = array_values($this->mergeItemsKeys('purchase_order_report_keys'));
|
$this->input['report_keys'] = array_values($this->mergeItemsKeys('purchase_order_report_keys'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_vendor_fields, $this->input['report_keys']));
|
||||||
|
|
||||||
$query = PurchaseOrder::query()
|
$query = PurchaseOrder::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->with('vendor')->where('company_id', $this->company->id)
|
->with('vendor')->where('company_id', $this->company->id)
|
||||||
@ -125,18 +127,18 @@ class PurchaseOrderItemExport extends BaseExport
|
|||||||
|
|
||||||
if (str_contains($key, "item.")) {
|
if (str_contains($key, "item.")) {
|
||||||
|
|
||||||
$key = str_replace("item.", "", $key);
|
$tmp_key = str_replace("item.", "", $key);
|
||||||
|
|
||||||
if($key == 'type_id') {
|
if($tmp_key == 'type_id') {
|
||||||
$keyval = 'type';
|
$tmp_key = 'type';
|
||||||
}
|
}
|
||||||
|
|
||||||
if($key == 'tax_id') {
|
if($tmp_key == 'tax_id') {
|
||||||
$keyval = 'tax_category';
|
$tmp_key = 'tax_category';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property_exists($item, $key)) {
|
if (property_exists($item, $tmp_key)) {
|
||||||
$item_array[$key] = $item->{$key};
|
$item_array[$key] = $item->{$tmp_key};
|
||||||
} else {
|
} else {
|
||||||
$item_array[$key] = '';
|
$item_array[$key] = '';
|
||||||
}
|
}
|
||||||
@ -145,6 +147,7 @@ class PurchaseOrderItemExport extends BaseExport
|
|||||||
|
|
||||||
$transformed_items = array_merge($transformed_purchase_order, $item_array);
|
$transformed_items = array_merge($transformed_purchase_order, $item_array);
|
||||||
$entity = $this->decorateAdvancedFields($purchase_order, $transformed_items);
|
$entity = $this->decorateAdvancedFields($purchase_order, $transformed_items);
|
||||||
|
$entity = array_merge(array_flip(array_values($this->input['report_keys'])), $entity);
|
||||||
|
|
||||||
$this->storage_array[] = $entity;
|
$this->storage_array[] = $entity;
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,8 @@ class QuoteExport extends BaseExport
|
|||||||
$this->input['report_keys'] = array_values($this->quote_report_keys);
|
$this->input['report_keys'] = array_values($this->quote_report_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
|
||||||
|
|
||||||
$query = Quote::query()
|
$query = Quote::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->with('client')
|
->with('client')
|
||||||
|
@ -57,6 +57,8 @@ class QuoteItemExport extends BaseExport
|
|||||||
$this->input['report_keys'] = array_values($this->mergeItemsKeys('quote_report_keys'));
|
$this->input['report_keys'] = array_values($this->mergeItemsKeys('quote_report_keys'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
|
||||||
|
|
||||||
$query = Quote::query()
|
$query = Quote::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->with('client')->where('company_id', $this->company->id)
|
->with('client')->where('company_id', $this->company->id)
|
||||||
@ -131,16 +133,16 @@ class QuoteItemExport extends BaseExport
|
|||||||
|
|
||||||
if (str_contains($key, "item.")) {
|
if (str_contains($key, "item.")) {
|
||||||
|
|
||||||
$key = str_replace("item.", "", $key);
|
$tmp_key = str_replace("item.", "", $key);
|
||||||
|
|
||||||
if($key == 'type_id')
|
if($tmp_key == 'type_id')
|
||||||
$key = 'type';
|
$tmp_key = 'type';
|
||||||
|
|
||||||
if($key == 'tax_id')
|
if($tmp_key == 'tax_id')
|
||||||
$key = 'tax_category';
|
$tmp_key = 'tax_category';
|
||||||
|
|
||||||
if (property_exists($item, $key)) {
|
if (property_exists($item, $tmp_key)) {
|
||||||
$item_array[$key] = $item->{$key};
|
$item_array[$key] = $item->{$tmp_key};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$item_array[$key] = '';
|
$item_array[$key] = '';
|
||||||
@ -150,6 +152,7 @@ class QuoteItemExport extends BaseExport
|
|||||||
|
|
||||||
$transformed_items = array_merge($transformed_quote, $item_array);
|
$transformed_items = array_merge($transformed_quote, $item_array);
|
||||||
$entity = $this->decorateAdvancedFields($quote, $transformed_items);
|
$entity = $this->decorateAdvancedFields($quote, $transformed_items);
|
||||||
|
$entity = array_merge(array_flip(array_values($this->input['report_keys'])), $entity);
|
||||||
|
|
||||||
$this->storage_array[] = $entity;
|
$this->storage_array[] = $entity;
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,8 @@ class RecurringInvoiceExport extends BaseExport
|
|||||||
$this->input['report_keys'] = array_values($this->recurring_invoice_report_keys);
|
$this->input['report_keys'] = array_values($this->recurring_invoice_report_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
|
||||||
|
|
||||||
$query = RecurringInvoice::query()
|
$query = RecurringInvoice::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->with('client')
|
->with('client')
|
||||||
@ -135,8 +137,8 @@ class RecurringInvoiceExport extends BaseExport
|
|||||||
$entity['client'] = $invoice->client->present()->name();
|
$entity['client'] = $invoice->client->present()->name();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array('status_id', $this->input['report_keys'])) {
|
if (in_array('recurring_invoice.status', $this->input['report_keys'])) {
|
||||||
$entity['status'] = $invoice->stringStatus($invoice->status_id);
|
$entity['recurring_invoice.status'] = $invoice->stringStatus($invoice->status_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array('project_id', $this->input['report_keys'])) {
|
if (in_array('project_id', $this->input['report_keys'])) {
|
||||||
|
@ -60,6 +60,8 @@ class TaskExport extends BaseExport
|
|||||||
$this->input['report_keys'] = array_values($this->task_report_keys);
|
$this->input['report_keys'] = array_values($this->task_report_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->input['report_keys'] = array_merge($this->input['report_keys'], array_diff($this->forced_client_fields, $this->input['report_keys']));
|
||||||
|
|
||||||
$query = Task::query()
|
$query = Task::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->where('company_id', $this->company->id)
|
->where('company_id', $this->company->id)
|
||||||
|
@ -30,6 +30,7 @@ class BankIntegrationFactory
|
|||||||
$bank_integration->bank_account_type = '';
|
$bank_integration->bank_account_type = '';
|
||||||
$bank_integration->balance = 0;
|
$bank_integration->balance = 0;
|
||||||
$bank_integration->currency = '';
|
$bank_integration->currency = '';
|
||||||
|
$bank_integration->auto_sync = 1;
|
||||||
|
|
||||||
return $bank_integration;
|
return $bank_integration;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,8 @@ class UserFactory
|
|||||||
$user->last_login = now();
|
$user->last_login = now();
|
||||||
$user->failed_logins = 0;
|
$user->failed_logins = 0;
|
||||||
$user->signature = '';
|
$user->signature = '';
|
||||||
$user->theme_id = 0;
|
$user->theme_id = 0;
|
||||||
|
$user->user_logged_in_notification = true;
|
||||||
|
|
||||||
return $user;
|
return $user;
|
||||||
}
|
}
|
||||||
|
@ -136,8 +136,13 @@ class TaskFilters extends QueryFilters
|
|||||||
|
|
||||||
$status_parameters = explode(',', $value);
|
$status_parameters = explode(',', $value);
|
||||||
|
|
||||||
if(count($status_parameters) >= 1)
|
if(count($status_parameters) >= 1){
|
||||||
$this->builder->whereIn('status_id', $this->transformKeys($status_parameters));
|
|
||||||
|
$this->builder->where(function ($query) use ($status_parameters) {
|
||||||
|
$query->whereIn('status_id', $this->transformKeys($status_parameters))->whereNull('invoice_id');
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ class AccountTransformer implements AccountTransformerInterface
|
|||||||
'id' => $account->id,
|
'id' => $account->id,
|
||||||
'account_type' => $account->CONTAINER,
|
'account_type' => $account->CONTAINER,
|
||||||
// 'account_name' => $account->accountName,
|
// 'account_name' => $account->accountName,
|
||||||
'account_name' => property_exists($account, 'accountName') ? $account->accountName : $account->nickname,
|
'account_name' => property_exists($account, 'accountName') ? $account->accountName : ($account->nickname ?? 'Unknown Account'),
|
||||||
'account_status' => $account_status,
|
'account_status' => $account_status,
|
||||||
'account_number' => property_exists($account, 'accountNumber') ? '**** ' . substr($account?->accountNumber, -7) : '',
|
'account_number' => property_exists($account, 'accountNumber') ? '**** ' . substr($account?->accountNumber, -7) : '',
|
||||||
'provider_account_id' => $account->providerAccountId,
|
'provider_account_id' => $account->providerAccountId,
|
||||||
|
@ -15,6 +15,7 @@ use App\Models\Company;
|
|||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
|
use BaconQrCode\Exception\InvalidArgumentException;
|
||||||
use BaconQrCode\Renderer\Image\SvgImageBackEnd;
|
use BaconQrCode\Renderer\Image\SvgImageBackEnd;
|
||||||
use BaconQrCode\Renderer\ImageRenderer;
|
use BaconQrCode\Renderer\ImageRenderer;
|
||||||
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
|
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
|
||||||
@ -58,10 +59,15 @@ class EpcQrGenerator
|
|||||||
<rect x='0' y='0' width='100%'' height='100%' />{$qr}</svg>";
|
<rect x='0' y='0' width='100%'' height='100%' />{$qr}</svg>";
|
||||||
|
|
||||||
} catch(\Throwable $e) {
|
} catch(\Throwable $e) {
|
||||||
|
nlog("EPC QR failure => ".$e->getMessage());
|
||||||
return '';
|
return '';
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
nlog("EPC QR failure => ".$e->getMessage());
|
||||||
return '';
|
return '';
|
||||||
}
|
} catch( InvalidArgumentException $e) {
|
||||||
|
nlog("EPC QR failure => ".$e->getMessage());
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -93,6 +99,7 @@ class EpcQrGenerator
|
|||||||
if (Ninja::isSelfHost() && isset($this->company?->custom_fields?->company1)) {
|
if (Ninja::isSelfHost() && isset($this->company?->custom_fields?->company1)) {
|
||||||
nlog('The IBAN field is required');
|
nlog('The IBAN field is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function formatMoney($value)
|
private function formatMoney($value)
|
||||||
|
@ -174,9 +174,14 @@ class SwissQrGenerator
|
|||||||
|
|
||||||
return $html;
|
return $html;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
foreach ($qrBill->getViolations() as $key => $violation) {
|
|
||||||
nlog("qr");
|
if(is_iterable($qrBill->getViolations())) {
|
||||||
nlog($violation);
|
|
||||||
|
foreach ($qrBill->getViolations() as $key => $violation) {
|
||||||
|
nlog("qr");
|
||||||
|
nlog($violation);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nlog($e->getMessage());
|
nlog($e->getMessage());
|
||||||
|
@ -87,7 +87,8 @@ class YodleeController extends BaseController
|
|||||||
$bank_integration->balance = $account['current_balance'];
|
$bank_integration->balance = $account['current_balance'];
|
||||||
$bank_integration->currency = $account['account_currency'];
|
$bank_integration->currency = $account['account_currency'];
|
||||||
$bank_integration->from_date = now()->subYear();
|
$bank_integration->from_date = now()->subYear();
|
||||||
|
$bank_integration->auto_sync = true;
|
||||||
|
|
||||||
$bank_integration->save();
|
$bank_integration->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,8 +167,8 @@ class YodleeController extends BaseController
|
|||||||
public function refreshWebhook(Request $request)
|
public function refreshWebhook(Request $request)
|
||||||
{
|
{
|
||||||
//we should ignore this one
|
//we should ignore this one
|
||||||
nlog("yodlee refresh");
|
// nlog("yodlee refresh");
|
||||||
nlog($request->all());
|
// nlog($request->all());
|
||||||
|
|
||||||
return response()->json(['message' => 'Success'], 200);
|
return response()->json(['message' => 'Success'], 200);
|
||||||
|
|
||||||
@ -236,8 +237,8 @@ class YodleeController extends BaseController
|
|||||||
public function refreshUpdatesWebhook(Request $request)
|
public function refreshUpdatesWebhook(Request $request)
|
||||||
{
|
{
|
||||||
//notifies a user if there are problems with yodlee accessing the data
|
//notifies a user if there are problems with yodlee accessing the data
|
||||||
nlog("update refresh");
|
// nlog("update refresh");
|
||||||
nlog($request->all());
|
// nlog($request->all());
|
||||||
|
|
||||||
return response()->json(['message' => 'Success'], 200);
|
return response()->json(['message' => 'Success'], 200);
|
||||||
|
|
||||||
|
@ -230,6 +230,8 @@ class BankIntegrationController extends BaseController
|
|||||||
$bank_integration->nickname = $account['nickname'];
|
$bank_integration->nickname = $account['nickname'];
|
||||||
$bank_integration->balance = $account['current_balance'];
|
$bank_integration->balance = $account['current_balance'];
|
||||||
$bank_integration->currency = $account['account_currency'];
|
$bank_integration->currency = $account['account_currency'];
|
||||||
|
$bank_integration->auto_sync = true;
|
||||||
|
|
||||||
$bank_integration->save();
|
$bank_integration->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,9 @@ namespace App\Http\Controllers;
|
|||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use Postmark\PostmarkClient;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use App\Factory\ClientFactory;
|
use App\Factory\ClientFactory;
|
||||||
use App\Filters\ClientFilters;
|
use App\Filters\ClientFilters;
|
||||||
@ -36,6 +39,8 @@ use App\Http\Requests\Client\CreateClientRequest;
|
|||||||
use App\Http\Requests\Client\UpdateClientRequest;
|
use App\Http\Requests\Client\UpdateClientRequest;
|
||||||
use App\Http\Requests\Client\UploadClientRequest;
|
use App\Http\Requests\Client\UploadClientRequest;
|
||||||
use App\Http\Requests\Client\DestroyClientRequest;
|
use App\Http\Requests\Client\DestroyClientRequest;
|
||||||
|
use App\Http\Requests\Client\ReactivateClientEmailRequest;
|
||||||
|
use App\Jobs\PostMark\ProcessPostmarkWebhook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ClientController.
|
* Class ClientController.
|
||||||
@ -219,7 +224,7 @@ class ClientController extends BaseController
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return $this->listResponse(Client::withTrashed()->company()->whereIn('id', $request->ids));
|
return $this->listResponse(Client::query()->withTrashed()->company()->whereIn('id', $request->ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -308,8 +313,66 @@ class ClientController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function updateTaxData(PurgeClientRequest $request, Client $client)
|
public function updateTaxData(PurgeClientRequest $request, Client $client)
|
||||||
{
|
{
|
||||||
(new UpdateTaxData($client, $client->company))->handle();
|
if($client->company->account->isPaid())
|
||||||
|
(new UpdateTaxData($client, $client->company))->handle();
|
||||||
|
|
||||||
return $this->itemResponse($client->fresh());
|
return $this->itemResponse($client->fresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reactivate a client email
|
||||||
|
*
|
||||||
|
* @param ReactivateClientEmailRequest $request
|
||||||
|
* @param string $bounce_id //could also be the invitationId
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function reactivateEmail(ReactivateClientEmailRequest $request, string $bounce_id)
|
||||||
|
{
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if(stripos($bounce_id, '-') !== false){
|
||||||
|
$log =
|
||||||
|
SystemLog::query()
|
||||||
|
->where('company_id', $user->company()->id)
|
||||||
|
->where('type_id', SystemLog::TYPE_WEBHOOK_RESPONSE)
|
||||||
|
->where('category_id', SystemLog::CATEGORY_MAIL)
|
||||||
|
->whereJsonContains('log', ['MessageID' => $bounce_id])
|
||||||
|
->orderBy('id', 'desc')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
$resolved_bounce_id = false;
|
||||||
|
|
||||||
|
if($log && ($log?->log['ID'] ?? false)){
|
||||||
|
$resolved_bounce_id = $log->log['ID'] ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$resolved_bounce_id){
|
||||||
|
$ppwebhook = new ProcessPostmarkWebhook([]);
|
||||||
|
$resolved_bounce_id = $ppwebhook->getBounceId($bounce_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$resolved_bounce_id){
|
||||||
|
return response()->json(['message' => 'Bounce ID not found'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$bounce_id = $resolved_bounce_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$postmark = new PostmarkClient(config('services.postmark.token'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$response = $postmark->activateBounce((int)$bounce_id);
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Success'], 200);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(\Exception $e){
|
||||||
|
|
||||||
|
return response()->json(['message' => $e->getMessage(), 400]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,11 +31,11 @@ class EmailHistoryController extends BaseController
|
|||||||
->where('category_id', SystemLog::CATEGORY_MAIL)
|
->where('category_id', SystemLog::CATEGORY_MAIL)
|
||||||
->orderBy('id', 'DESC')
|
->orderBy('id', 'DESC')
|
||||||
->cursor()
|
->cursor()
|
||||||
->map(function ($system_log) {
|
->filter(function ($system_log) {
|
||||||
if(($system_log->log['history'] && $system_log->log['history']['events'] && count($system_log->log['history']['events']) >=1) ?? false) {
|
return (isset($system_log->log['history']) && isset($system_log->log['history']['events']) && count($system_log->log['history']['events']) >=1) !== false;
|
||||||
return $system_log->log['history'];
|
})->map(function ($system_log) {
|
||||||
}
|
return $system_log->log['history'];
|
||||||
});
|
})->values()->all();
|
||||||
|
|
||||||
return response()->json($data, 200);
|
return response()->json($data, 200);
|
||||||
|
|
||||||
@ -51,16 +51,17 @@ class EmailHistoryController extends BaseController
|
|||||||
/** @var \App\Models\User $user */
|
/** @var \App\Models\User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
|
|
||||||
$data = SystemLog::where('company_id', $user->company()->id)
|
$data = SystemLog::where('company_id', $user->company()->id)
|
||||||
->where('category_id', SystemLog::CATEGORY_MAIL)
|
->where('category_id', SystemLog::CATEGORY_MAIL)
|
||||||
->whereJsonContains('log->history->entity_id', $this->encodePrimaryKey($request->entity_id))
|
->whereJsonContains('log->history->entity_id', $this->encodePrimaryKey($request->entity_id))
|
||||||
->orderBy('id', 'DESC')
|
->orderBy('id', 'DESC')
|
||||||
->cursor()
|
->cursor()
|
||||||
->map(function ($system_log) {
|
->filter(function ($system_log) {
|
||||||
if(($system_log->log['history'] && $system_log->log['history']['events'] && count($system_log->log['history']['events']) >=1) ?? false) {
|
return ($system_log->log['history'] && isset($system_log->log['history']['events']) && count($system_log->log['history']['events']) >=1) !== false;
|
||||||
return $system_log->log['history'];
|
})->map(function ($system_log) {
|
||||||
}
|
return $system_log->log['history'];
|
||||||
});
|
})->values()->all();
|
||||||
|
|
||||||
return response()->json($data, 200);
|
return response()->json($data, 200);
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ class PostMarkController extends BaseController
|
|||||||
public function webhook(Request $request)
|
public function webhook(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->header('X-API-SECURITY') && $request->header('X-API-SECURITY') == config('services.postmark.token')) {
|
if ($request->header('X-API-SECURITY') && $request->header('X-API-SECURITY') == config('services.postmark.token')) {
|
||||||
ProcessPostmarkWebhook::dispatch($request->all());
|
ProcessPostmarkWebhook::dispatch($request->all())->delay(10);
|
||||||
|
|
||||||
return response()->json(['message' => 'Success'], 200);
|
return response()->json(['message' => 'Success'], 200);
|
||||||
}
|
}
|
||||||
|
@ -11,42 +11,43 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\DataMapper\Analytics\LivePreview;
|
use App\Utils\Ninja;
|
||||||
use App\Factory\CreditFactory;
|
use App\Models\Quote;
|
||||||
use App\Factory\InvoiceFactory;
|
|
||||||
use App\Factory\QuoteFactory;
|
|
||||||
use App\Factory\RecurringInvoiceFactory;
|
|
||||||
use App\Http\Requests\Preview\DesignPreviewRequest;
|
|
||||||
use App\Http\Requests\Preview\PreviewInvoiceRequest;
|
|
||||||
use App\Jobs\Util\PreviewPdf;
|
|
||||||
use App\Libraries\MultiDB;
|
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\ClientContact;
|
|
||||||
use App\Models\Credit;
|
use App\Models\Credit;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\InvoiceInvitation;
|
use App\Utils\HtmlEngine;
|
||||||
use App\Models\Quote;
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Factory\QuoteFactory;
|
||||||
use App\Repositories\CreditRepository;
|
use App\Jobs\Util\PreviewPdf;
|
||||||
use App\Repositories\InvoiceRepository;
|
use App\Models\ClientContact;
|
||||||
use App\Repositories\QuoteRepository;
|
|
||||||
use App\Repositories\RecurringInvoiceRepository;
|
|
||||||
use App\Services\Pdf\PdfMock;
|
use App\Services\Pdf\PdfMock;
|
||||||
|
use App\Factory\CreditFactory;
|
||||||
|
use App\Factory\InvoiceFactory;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
|
use App\Utils\PhantomJS\Phantom;
|
||||||
|
use App\Models\InvoiceInvitation;
|
||||||
use App\Services\PdfMaker\Design;
|
use App\Services\PdfMaker\Design;
|
||||||
|
use App\Utils\HostedPDF\NinjaPdf;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use App\Services\PdfMaker\PdfMaker;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use App\Repositories\QuoteRepository;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use App\Repositories\CreditRepository;
|
||||||
|
use App\Utils\Traits\MakesInvoiceHtml;
|
||||||
|
use Turbo124\Beacon\Facades\LightLogs;
|
||||||
|
use App\Repositories\InvoiceRepository;
|
||||||
|
use App\Utils\Traits\Pdf\PageNumbering;
|
||||||
|
use App\Factory\RecurringInvoiceFactory;
|
||||||
|
use Illuminate\Support\Facades\Response;
|
||||||
|
use App\DataMapper\Analytics\LivePreview;
|
||||||
|
use App\Repositories\RecurringInvoiceRepository;
|
||||||
|
use App\Http\Requests\Preview\DesignPreviewRequest;
|
||||||
use App\Services\PdfMaker\Design as PdfDesignModel;
|
use App\Services\PdfMaker\Design as PdfDesignModel;
|
||||||
use App\Services\PdfMaker\Design as PdfMakerDesign;
|
use App\Services\PdfMaker\Design as PdfMakerDesign;
|
||||||
use App\Services\PdfMaker\PdfMaker;
|
use App\Http\Requests\Preview\PreviewInvoiceRequest;
|
||||||
use App\Utils\HostedPDF\NinjaPdf;
|
|
||||||
use App\Utils\HtmlEngine;
|
|
||||||
use App\Utils\Ninja;
|
|
||||||
use App\Utils\PhantomJS\Phantom;
|
|
||||||
use App\Utils\Traits\MakesHash;
|
|
||||||
use App\Utils\Traits\MakesInvoiceHtml;
|
|
||||||
use App\Utils\Traits\Pdf\PageNumbering;
|
|
||||||
use Illuminate\Support\Facades\App;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Response;
|
|
||||||
use Turbo124\Beacon\Facades\LightLogs;
|
|
||||||
|
|
||||||
class PreviewController extends BaseController
|
class PreviewController extends BaseController
|
||||||
{
|
{
|
||||||
@ -56,15 +57,181 @@ class PreviewController extends BaseController
|
|||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function purgeCache()
|
||||||
|
{
|
||||||
|
Cache::pull("preview_".auth()->user()->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refactor - 2023-10-19
|
||||||
|
*
|
||||||
|
* New method does not require Transactions.
|
||||||
|
*
|
||||||
|
* @param PreviewInvoiceRequest $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function live(PreviewInvoiceRequest $request): mixed
|
||||||
|
{
|
||||||
|
|
||||||
|
if (Ninja::isHosted() && !in_array($request->getHost(), ['preview.invoicing.co','staging.invoicing.co'])) {
|
||||||
|
return response()->json(['message' => 'This server cannot handle this request.'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$start = microtime(true);
|
||||||
|
|
||||||
|
/** Build models */
|
||||||
|
$invitation = $request->resolveInvitation();
|
||||||
|
$client = $request->getClient();
|
||||||
|
$settings = $client->getMergedSettings();
|
||||||
|
|
||||||
|
/** Set translations */
|
||||||
|
App::forgetInstance('translator');
|
||||||
|
$t = app('translator');
|
||||||
|
App::setLocale($invitation->contact->preferredLocale());
|
||||||
|
$t->replace(Ninja::transformTranslations($settings));
|
||||||
|
|
||||||
|
$entity_prop = str_replace("recurring_", "", $request->entity);
|
||||||
|
$entity_obj = $invitation->{$request->entity};
|
||||||
|
$entity_obj->fill($request->all());
|
||||||
|
|
||||||
|
/** Update necessary objecty props */
|
||||||
|
if(!$entity_obj->id) {
|
||||||
|
$entity_obj->design_id = intval($this->decodePrimaryKey($settings->{$entity_prop."_design_id"}));
|
||||||
|
$entity_obj->footer = empty($entity_obj->footer) ? $settings->{$entity_prop."_footer"} : $entity_obj->footer;
|
||||||
|
$entity_obj->terms = empty($entity_obj->term) ? $settings->{$entity_prop."_terms"} : $entity_obj->terms;
|
||||||
|
$entity_obj->public_notes = empty($entity_obj->public_notes) ? $request->getClient()->public_notes : $entity_obj->public_notes;
|
||||||
|
$invitation->{$request->entity} = $entity_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(empty($entity_obj->design_id))
|
||||||
|
$entity_obj->design_id = intval($this->decodePrimaryKey($settings->{$entity_prop."_design_id"}));
|
||||||
|
|
||||||
|
/** Generate variables */
|
||||||
|
$html = new HtmlEngine($invitation);
|
||||||
|
$html->settings = $settings;
|
||||||
|
$variables = $html->generateLabelsAndValues();
|
||||||
|
|
||||||
|
$design = \App\Models\Design::query()->withTrashed()->find($entity_obj->design_id ?? 2);
|
||||||
|
|
||||||
|
/* Catch all in case migration doesn't pass back a valid design */
|
||||||
|
if (! $design) {
|
||||||
|
$design = \App\Models\Design::query()->find(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($design->is_custom) {
|
||||||
|
$options = [
|
||||||
|
'custom_partials' => json_decode(json_encode($design->design), true),
|
||||||
|
];
|
||||||
|
$template = new PdfMakerDesign(PdfDesignModel::CUSTOM, $options);
|
||||||
|
} else {
|
||||||
|
$template = new PdfMakerDesign(strtolower($design->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
$state = [
|
||||||
|
'template' => $template->elements([
|
||||||
|
'client' => $client,
|
||||||
|
'entity' => $entity_obj,
|
||||||
|
'pdf_variables' => (array) $settings->pdf_variables,
|
||||||
|
'$product' => $design->design->product,
|
||||||
|
'variables' => $variables,
|
||||||
|
]),
|
||||||
|
'variables' => $variables,
|
||||||
|
'options' => [
|
||||||
|
'all_pages_header' => $client->getSetting('all_pages_header'),
|
||||||
|
'all_pages_footer' => $client->getSetting('all_pages_footer'),
|
||||||
|
],
|
||||||
|
'process_markdown' => $client->company->markdown_enabled,
|
||||||
|
];
|
||||||
|
|
||||||
|
$maker = new PdfMaker($state);
|
||||||
|
|
||||||
|
$maker
|
||||||
|
->design($template)
|
||||||
|
->build();
|
||||||
|
|
||||||
|
/** Generate HTML */
|
||||||
|
$html = $maker->getCompiledHTML(true);
|
||||||
|
|
||||||
|
if (request()->query('html') == 'true')
|
||||||
|
return $html;
|
||||||
|
|
||||||
|
//if phantom js...... inject here..
|
||||||
|
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
|
||||||
|
return (new Phantom)->convertHtmlToPdf($html);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
$company = $user->company();
|
||||||
|
|
||||||
|
if (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') {
|
||||||
|
|
||||||
|
$pdf = (new NinjaPdf())->build($html);
|
||||||
|
$numbered_pdf = $this->pageNumbering($pdf, $company);
|
||||||
|
|
||||||
|
if ($numbered_pdf)
|
||||||
|
$pdf = $numbered_pdf;
|
||||||
|
|
||||||
|
return $pdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdf = (new PreviewPdf($html, $company))->handle();
|
||||||
|
|
||||||
|
if (Ninja::isHosted()) {
|
||||||
|
LightLogs::create(new LivePreview())
|
||||||
|
->increment()
|
||||||
|
->batch();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return PDF */
|
||||||
|
return response()->streamDownload(function () use ($pdf) {
|
||||||
|
echo $pdf;
|
||||||
|
}, 'preview.pdf', [
|
||||||
|
'Content-Disposition' => 'inline',
|
||||||
|
'Content-Type' => 'application/pdf',
|
||||||
|
'Cache-Control:' => 'no-cache',
|
||||||
|
'Server-Timing' => microtime(true)-$start
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mocked PDF for the invoice design preview.
|
||||||
|
*
|
||||||
|
* Only used in Settings > Invoice Design as a general overview
|
||||||
|
*
|
||||||
|
* @param DesignPreviewRequest $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function design(DesignPreviewRequest $request): mixed
|
||||||
|
{
|
||||||
|
$start = microtime(true);
|
||||||
|
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
/** @var \App\Models\Company $company */
|
||||||
|
$company = $user->company();
|
||||||
|
|
||||||
|
$pdf = (new PdfMock($request->all(), $company))->build()->getPdf();
|
||||||
|
|
||||||
|
$response = Response::make($pdf, 200);
|
||||||
|
$response->header('Content-Type', 'application/pdf');
|
||||||
|
$response->header('Server-Timing', microtime(true)-$start);
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a template filled with entity variables.
|
* Returns a template filled with entity variables.
|
||||||
*
|
*
|
||||||
|
* Used in the Custom Designer to preview design changes
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function show()
|
public function show()
|
||||||
{
|
{
|
||||||
if (request()->has('entity') &&
|
if (request()->has('entity') &&
|
||||||
@ -72,6 +239,7 @@ class PreviewController extends BaseController
|
|||||||
! empty(request()->input('entity')) &&
|
! empty(request()->input('entity')) &&
|
||||||
! empty(request()->input('entity_id')) &&
|
! empty(request()->input('entity_id')) &&
|
||||||
request()->has('body')) {
|
request()->has('body')) {
|
||||||
|
|
||||||
$design_object = json_decode(json_encode(request()->input('design')));
|
$design_object = json_decode(json_encode(request()->input('design')));
|
||||||
|
|
||||||
if (! is_object($design_object)) {
|
if (! is_object($design_object)) {
|
||||||
@ -128,55 +296,57 @@ class PreviewController extends BaseController
|
|||||||
return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
|
return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** @var \App\Models\User $user */
|
/** @var \App\Models\User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
$company = $user->company();
|
$company = $user->company();
|
||||||
|
|
||||||
if (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') {
|
if (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') {
|
||||||
|
|
||||||
$pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true));
|
$pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true));
|
||||||
|
|
||||||
$numbered_pdf = $this->pageNumbering($pdf, $company);
|
$numbered_pdf = $this->pageNumbering($pdf, $company);
|
||||||
|
if ($numbered_pdf)
|
||||||
if ($numbered_pdf) {
|
|
||||||
$pdf = $numbered_pdf;
|
$pdf = $numbered_pdf;
|
||||||
}
|
|
||||||
|
|
||||||
return $pdf;
|
return $pdf;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$file_path = (new PreviewPdf($maker->getCompiledHTML(true), $company))->handle();
|
$pdf = (new PreviewPdf($maker->getCompiledHTML(true), $company))->handle();
|
||||||
|
|
||||||
|
return response()->streamDownload(function () use ($pdf) {
|
||||||
|
echo $pdf;
|
||||||
|
}, 'preview.pdf', [
|
||||||
|
'Content-Disposition' => 'inline',
|
||||||
|
'Content-Type' => 'application/pdf',
|
||||||
|
'Cache-Control:' => 'no-cache',
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->blankEntity();
|
return $this->blankEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function design(DesignPreviewRequest $request)
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated due to usage of transactions
|
||||||
|
*
|
||||||
|
* @param PreviewInvoiceRequest $request
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function livex(PreviewInvoiceRequest $request)
|
||||||
{
|
{
|
||||||
/** @var \App\Models\User $user */
|
|
||||||
$user = auth()->user();
|
|
||||||
|
|
||||||
/** @var \App\Models\Company $company */
|
if(Cache::has("preview_".auth()->user()->id))
|
||||||
$company = $user->company();
|
return response()->json(['message' => 'Please wait a few seconds before trying again, this many requests are not good.'], 400);
|
||||||
|
|
||||||
$pdf = (new PdfMock($request->all(), $company))->build()->getPdf();
|
|
||||||
|
|
||||||
$response = Response::make($pdf, 200);
|
|
||||||
$response->header('Content-Type', 'application/pdf');
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function live(PreviewInvoiceRequest $request)
|
|
||||||
{
|
|
||||||
if (Ninja::isHosted() && !in_array($request->getHost(), ['preview.invoicing.co','staging.invoicing.co'])) {
|
if (Ninja::isHosted() && !in_array($request->getHost(), ['preview.invoicing.co','staging.invoicing.co'])) {
|
||||||
return response()->json(['message' => 'This server cannot handle this request.'], 400);
|
return response()->json(['message' => 'This server cannot handle this request.'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Cache::put("preview_".auth()->user()->id, 60);
|
||||||
|
|
||||||
$start = microtime(true);
|
$start = microtime(true);
|
||||||
|
|
||||||
/** @var \App\Models\User $user */
|
/** @var \App\Models\User $user */
|
||||||
@ -287,9 +457,13 @@ class PreviewController extends BaseController
|
|||||||
DB::connection(config('database.default'))->rollBack();
|
DB::connection(config('database.default'))->rollBack();
|
||||||
|
|
||||||
if (request()->query('html') == 'true') {
|
if (request()->query('html') == 'true') {
|
||||||
|
$this->purgeCache();
|
||||||
return $maker->getCompiledHTML();
|
return $maker->getCompiledHTML();
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
|
||||||
|
$this->purgeCache();
|
||||||
|
|
||||||
DB::connection(config('database.default'))->rollBack();
|
DB::connection(config('database.default'))->rollBack();
|
||||||
|
|
||||||
@ -302,6 +476,7 @@ class PreviewController extends BaseController
|
|||||||
|
|
||||||
//if phantom js...... inject here..
|
//if phantom js...... inject here..
|
||||||
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
|
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
|
||||||
|
$this->purgeCache();
|
||||||
return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
|
return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +494,7 @@ class PreviewController extends BaseController
|
|||||||
if ($numbered_pdf) {
|
if ($numbered_pdf) {
|
||||||
$pdf = $numbered_pdf;
|
$pdf = $numbered_pdf;
|
||||||
}
|
}
|
||||||
|
$this->purgeCache();
|
||||||
return $pdf;
|
return $pdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +510,7 @@ class PreviewController extends BaseController
|
|||||||
$response->header('Content-Type', 'application/pdf');
|
$response->header('Content-Type', 'application/pdf');
|
||||||
$response->header('Server-Timing', microtime(true)-$start);
|
$response->header('Server-Timing', microtime(true)-$start);
|
||||||
|
|
||||||
|
$this->purgeCache();
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,7 +698,6 @@ class PreviewController extends BaseController
|
|||||||
|
|
||||||
$response = Response::make($file_path, 200);
|
$response = Response::make($file_path, 200);
|
||||||
$response->header('Content-Type', 'application/pdf');
|
$response->header('Content-Type', 'application/pdf');
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ class ProtectedDownloadController extends BaseController
|
|||||||
|
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
|
/** @var string $hashed_path */
|
||||||
$hashed_path = Cache::pull($request->hash);
|
$hashed_path = Cache::pull($request->hash);
|
||||||
|
|
||||||
if (!$hashed_path) {
|
if (!$hashed_path) {
|
||||||
|
@ -157,6 +157,7 @@ class RecurringInvoiceController extends BaseController
|
|||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
$recurring_invoice = RecurringInvoiceFactory::create($user->company()->id, $user->id);
|
$recurring_invoice = RecurringInvoiceFactory::create($user->company()->id, $user->id);
|
||||||
|
$recurring_invoice->auto_bill = $user->company()->settings->auto_bill;
|
||||||
|
|
||||||
return $this->itemResponse($recurring_invoice);
|
return $this->itemResponse($recurring_invoice);
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,7 @@ class StripeConnectController extends BaseController
|
|||||||
'refresh_token' => $response->refresh_token,
|
'refresh_token' => $response->refresh_token,
|
||||||
'access_token' => $response->access_token,
|
'access_token' => $response->access_token,
|
||||||
'appleDomainVerification' => '',
|
'appleDomainVerification' => '',
|
||||||
|
// "statementDescriptor" => "",
|
||||||
];
|
];
|
||||||
|
|
||||||
$company_gateway->setConfig($payload);
|
$company_gateway->setConfig($payload);
|
||||||
|
@ -39,11 +39,11 @@ class TasksTable extends Component
|
|||||||
->where('is_deleted', false)
|
->where('is_deleted', false)
|
||||||
->where('client_id', auth()->guard('contact')->user()->client_id);
|
->where('client_id', auth()->guard('contact')->user()->client_id);
|
||||||
|
|
||||||
if ($this->company->getSetting('show_all_tasks_client_portal') === 'invoiced') {
|
if ( auth()->guard('contact')->user()->client->getSetting('show_all_tasks_client_portal') === 'invoiced') {
|
||||||
$query = $query->whereNotNull('invoice_id');
|
$query = $query->whereNotNull('invoice_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->company->getSetting('show_all_tasks_client_portal') === 'uninvoiced') {
|
if ( auth()->guard('contact')->user()->client->getSetting('show_all_tasks_client_portal') === 'uninvoiced') {
|
||||||
$query = $query->whereNull('invoice_id');
|
$query = $query->whereNull('invoice_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
app/Http/Requests/Client/ReactivateClientEmailRequest.php
Normal file
28
app/Http/Requests/Client/ReactivateClientEmailRequest.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Client;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class ReactivateClientEmailRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -180,8 +180,6 @@ class StoreClientRequest extends Request
|
|||||||
public function messages()
|
public function messages()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
// 'unique' => ctrans('validation.unique', ['attribute' => ['email','number']),
|
|
||||||
//'required' => trans('validation.required', ['attribute' => 'email']),
|
|
||||||
'contacts.*.email.required' => ctrans('validation.email', ['attribute' => 'email']),
|
'contacts.*.email.required' => ctrans('validation.email', ['attribute' => 'email']),
|
||||||
'currency_code' => 'Currency code does not exist',
|
'currency_code' => 'Currency code does not exist',
|
||||||
];
|
];
|
||||||
|
@ -28,4 +28,15 @@ class ProcessInvoicesInBulkRequest extends FormRequest
|
|||||||
'invoices' => ['array'],
|
'invoices' => ['array'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function prepareForValidation()
|
||||||
|
{
|
||||||
|
$input = $this->all();
|
||||||
|
|
||||||
|
if(isset($input['invoices'])){
|
||||||
|
$input['invoices'] = array_unique($input['invoices']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->replace($input);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ class RegisterRequest extends FormRequest
|
|||||||
$rules = [];
|
$rules = [];
|
||||||
|
|
||||||
foreach ($this->company()->client_registration_fields as $field) {
|
foreach ($this->company()->client_registration_fields as $field) {
|
||||||
if ($field['visible']) {
|
if ($field['visible'] ?? true) {
|
||||||
$rules[$field['key']] = $field['required'] ? ['bail','required'] : ['sometimes'];
|
$rules[$field['key']] = $field['required'] ? ['bail','required'] : ['sometimes'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,13 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\GroupSetting;
|
namespace App\Http\Requests\GroupSetting;
|
||||||
|
|
||||||
use App\DataMapper\ClientSettings;
|
|
||||||
use App\Http\Requests\Request;
|
|
||||||
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
|
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Models\GroupSetting;
|
use App\Models\GroupSetting;
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\DataMapper\ClientSettings;
|
||||||
|
use App\DataMapper\CompanySettings;
|
||||||
|
use App\DataMapper\Settings\SettingsData;
|
||||||
|
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
|
||||||
|
|
||||||
class StoreGroupSettingRequest extends Request
|
class StoreGroupSettingRequest extends Request
|
||||||
{
|
{
|
||||||
@ -26,12 +28,18 @@ class StoreGroupSettingRequest extends Request
|
|||||||
*/
|
*/
|
||||||
public function authorize() : bool
|
public function authorize() : bool
|
||||||
{
|
{
|
||||||
return auth()->user()->can('create', GroupSetting::class) && auth()->user()->account->hasFeature(Account::FEATURE_API);
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
return $user->can('create', GroupSetting::class) && $user->account->hasFeature(Account::FEATURE_API);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
$rules['name'] = 'required|unique:group_settings,name,null,null,company_id,'.auth()->user()->companyId();
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
$rules['name'] = 'required|unique:group_settings,name,null,null,company_id,'.$user->companyId();
|
||||||
|
|
||||||
$rules['settings'] = new ValidClientGroupSettingsRule();
|
$rules['settings'] = new ValidClientGroupSettingsRule();
|
||||||
|
|
||||||
@ -42,15 +50,12 @@ class StoreGroupSettingRequest extends Request
|
|||||||
{
|
{
|
||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
$group_settings = ClientSettings::defaults();
|
if (array_key_exists('settings', $input)) {
|
||||||
|
$input['settings'] = $this->filterSaveableSettings($input['settings']);
|
||||||
if (array_key_exists('settings', $input) && ! empty($input['settings'])) {
|
}
|
||||||
foreach ($input['settings'] as $key => $value) {
|
else {
|
||||||
$group_settings->{$key} = $value;
|
$input['settings'] = (array)ClientSettings::defaults();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$input['settings'] = (array)$group_settings;
|
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
@ -61,4 +66,38 @@ class StoreGroupSettingRequest extends Request
|
|||||||
'settings' => 'settings must be a valid json structure',
|
'settings' => 'settings must be a valid json structure',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For the hosted platform, we restrict the feature settings.
|
||||||
|
*
|
||||||
|
* This method will trim the company settings object
|
||||||
|
* down to the free plan setting properties which
|
||||||
|
* are saveable
|
||||||
|
*
|
||||||
|
* @param object $settings
|
||||||
|
* @return array $settings
|
||||||
|
*/
|
||||||
|
private function filterSaveableSettings($settings)
|
||||||
|
{
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
$settings_data = new SettingsData();
|
||||||
|
$settings = $settings_data->cast($settings)->toObject();
|
||||||
|
|
||||||
|
if (! $user->account->isFreeHostedClient()) {
|
||||||
|
return (array)$settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
$saveable_casts = CompanySettings::$free_plan_casts;
|
||||||
|
|
||||||
|
foreach ($settings as $key => $value) {
|
||||||
|
if (! array_key_exists($key, $saveable_casts)) {
|
||||||
|
unset($settings->{$key});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (array)$settings;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,9 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\GroupSetting;
|
namespace App\Http\Requests\GroupSetting;
|
||||||
|
|
||||||
use App\DataMapper\CompanySettings;
|
|
||||||
use App\Http\Requests\Request;
|
use App\Http\Requests\Request;
|
||||||
|
use App\DataMapper\CompanySettings;
|
||||||
|
use App\DataMapper\Settings\SettingsData;
|
||||||
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
|
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
|
||||||
|
|
||||||
class UpdateGroupSettingRequest extends Request
|
class UpdateGroupSettingRequest extends Request
|
||||||
@ -62,10 +63,14 @@ class UpdateGroupSettingRequest extends Request
|
|||||||
*/
|
*/
|
||||||
private function filterSaveableSettings($settings)
|
private function filterSaveableSettings($settings)
|
||||||
{
|
{
|
||||||
$account = $this->group_setting->company->account;
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
if (! $account->isFreeHostedClient()) {
|
$settings_data = new SettingsData();
|
||||||
return $settings;
|
$settings = $settings_data->cast($settings)->toObject();
|
||||||
|
|
||||||
|
if (! $user->account->isFreeHostedClient()) {
|
||||||
|
return (array)$settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
$saveable_casts = CompanySettings::$free_plan_casts;
|
$saveable_casts = CompanySettings::$free_plan_casts;
|
||||||
@ -75,7 +80,7 @@ class UpdateGroupSettingRequest extends Request
|
|||||||
unset($settings->{$key});
|
unset($settings->{$key});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (array)$settings;
|
return (array)$settings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ class StorePaymentRequest extends Request
|
|||||||
$credits_total = 0;
|
$credits_total = 0;
|
||||||
|
|
||||||
if (isset($input['client_id']) && is_string($input['client_id'])) {
|
if (isset($input['client_id']) && is_string($input['client_id'])) {
|
||||||
$input['client_id'] = $this->decodePrimaryKey($input['client_id']);
|
$input['client_id'] = $this->decodePrimaryKey($input['client_id'], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array_key_exists('assigned_user_id', $input) && is_string($input['assigned_user_id'])) {
|
if (array_key_exists('assigned_user_id', $input) && is_string($input['assigned_user_id'])) {
|
||||||
|
@ -32,11 +32,14 @@ class DesignPreviewRequest extends Request
|
|||||||
*/
|
*/
|
||||||
public function authorize() : bool
|
public function authorize() : bool
|
||||||
{
|
{
|
||||||
return auth()->user()->can('create', Invoice::class) ||
|
/** @var \App\Models\User $user */
|
||||||
auth()->user()->can('create', Quote::class) ||
|
$user = auth()->user();
|
||||||
auth()->user()->can('create', RecurringInvoice::class) ||
|
|
||||||
auth()->user()->can('create', Credit::class) ||
|
return $user->can('create', Invoice::class) ||
|
||||||
auth()->user()->can('create', PurchaseOrder::class);
|
$user->can('create', Quote::class) ||
|
||||||
|
$user->can('create', RecurringInvoice::class) ||
|
||||||
|
$user->can('create', Credit::class) ||
|
||||||
|
$user->can('create', PurchaseOrder::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules()
|
public function rules()
|
||||||
|
@ -11,15 +11,29 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Preview;
|
namespace App\Http\Requests\Preview;
|
||||||
|
|
||||||
|
use App\Models\Quote;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\Credit;
|
||||||
|
use App\Models\Invoice;
|
||||||
use App\Http\Requests\Request;
|
use App\Http\Requests\Request;
|
||||||
use App\Utils\Traits\CleanLineItems;
|
use App\Models\QuoteInvitation;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use App\Models\CreditInvitation;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
|
use App\Models\InvoiceInvitation;
|
||||||
|
use App\Utils\Traits\CleanLineItems;
|
||||||
|
use App\Models\RecurringInvoiceInvitation;
|
||||||
|
|
||||||
class PreviewInvoiceRequest extends Request
|
class PreviewInvoiceRequest extends Request
|
||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
use CleanLineItems;
|
use CleanLineItems;
|
||||||
|
|
||||||
|
private string $entity_plural = '';
|
||||||
|
|
||||||
|
private ?Client $client = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the user is authorized to make this request.
|
* Determine if the user is authorized to make this request.
|
||||||
*
|
*
|
||||||
@ -27,20 +41,32 @@ class PreviewInvoiceRequest extends Request
|
|||||||
*/
|
*/
|
||||||
public function authorize() : bool
|
public function authorize() : bool
|
||||||
{
|
{
|
||||||
return auth()->user()->hasIntersectPermissionsOrAdmin(['view_invoice', 'view_quote', 'view_recurring_invoice', 'view_credit', 'create_invoice', 'create_quote', 'create_recurring_invoice', 'create_credit','edit_invoice', 'edit_quote', 'edit_recurring_invoice', 'edit_credit']);
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
return $user->hasIntersectPermissionsOrAdmin(['view_invoice', 'view_quote', 'view_recurring_invoice', 'view_credit', 'create_invoice', 'create_quote', 'create_recurring_invoice', 'create_credit','edit_invoice', 'edit_quote', 'edit_recurring_invoice', 'edit_credit']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
$rules = [];
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
$rules['number'] = ['nullable'];
|
return [
|
||||||
|
'number' => 'nullable',
|
||||||
|
'entity' => 'bail|sometimes|in:invoice,quote,credit,recurring_invoice',
|
||||||
|
'entity_id' => ['bail','sometimes','integer',Rule::exists($this->entity_plural, 'id')->where('is_deleted',0)->where('company_id', $user->company()->id)],
|
||||||
|
'client_id' => ['required', Rule::exists(Client::class, 'id')->where('is_deleted', 0)->where('company_id', $user->company()->id)],
|
||||||
|
];
|
||||||
|
|
||||||
return $rules;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function prepareForValidation()
|
public function prepareForValidation()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
$input = $this->decodePrimaryKeys($input);
|
$input = $this->decodePrimaryKeys($input);
|
||||||
@ -50,6 +76,112 @@ class PreviewInvoiceRequest extends Request
|
|||||||
$input['balance'] = 0;
|
$input['balance'] = 0;
|
||||||
$input['number'] = isset($input['number']) ? $input['number'] : ctrans('texts.live_preview').' #'.rand(0, 1000);
|
$input['number'] = isset($input['number']) ? $input['number'] : ctrans('texts.live_preview').' #'.rand(0, 1000);
|
||||||
|
|
||||||
|
if($input['entity_id'] ?? false)
|
||||||
|
$input['entity_id'] = $this->decodePrimaryKey($input['entity_id'], true);
|
||||||
|
|
||||||
|
$this->convertEntityPlural($input['entity'] ?? 'invoice');
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function resolveInvitation()
|
||||||
|
{
|
||||||
|
$invitation = false;
|
||||||
|
|
||||||
|
if(! $this->entity_id ?? false)
|
||||||
|
return $this->stubInvitation();
|
||||||
|
|
||||||
|
match($this->entity){
|
||||||
|
'invoice' => $invitation = InvoiceInvitation::withTrashed()->where('invoice_id', $this->entity_id)->first(),
|
||||||
|
'quote' => $invitation = QuoteInvitation::withTrashed()->where('quote_id', $this->entity_id)->first(),
|
||||||
|
'credit' => $invitation = CreditInvitation::withTrashed()->where('credit_id', $this->entity_id)->first(),
|
||||||
|
'recurring_invoice' => $invitation = RecurringInvoiceInvitation::withTrashed()->where('recurring_invoice_id', $this->entity_id)->first(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if($invitation)
|
||||||
|
return $invitation;
|
||||||
|
|
||||||
|
$invitation = $this->stubInvitation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClient(): ?Client
|
||||||
|
{
|
||||||
|
if(!$this->client)
|
||||||
|
$this->client = Client::query()->with('contacts', 'company', 'user')->withTrashed()->find($this->client_id);
|
||||||
|
|
||||||
|
return $this->client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setClient(Client $client): self
|
||||||
|
{
|
||||||
|
$this->client = $client;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stubInvitation()
|
||||||
|
{
|
||||||
|
$client = Client::query()->with('contacts', 'company', 'user')->withTrashed()->find($this->client_id);
|
||||||
|
$this->setClient($client);
|
||||||
|
$invitation = false;
|
||||||
|
|
||||||
|
match($this->entity) {
|
||||||
|
'invoice' => $invitation = InvoiceInvitation::factory()->make(),
|
||||||
|
'quote' => $invitation = QuoteInvitation::factory()->make(),
|
||||||
|
'credit' => $invitation = CreditInvitation::factory()->make(),
|
||||||
|
'recurring_invoice' => $invitation = RecurringInvoiceInvitation::factory()->make(),
|
||||||
|
default => $invitation = InvoiceInvitation::factory()->make(),
|
||||||
|
};
|
||||||
|
|
||||||
|
$entity = $this->stubEntity($client);
|
||||||
|
|
||||||
|
$invitation->make();
|
||||||
|
$invitation->setRelation($this->entity, $entity);
|
||||||
|
$invitation->setRelation('contact', $client->contacts->first()->load('client.company'));
|
||||||
|
$invitation->setRelation('company', $client->company);
|
||||||
|
|
||||||
|
return $invitation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function stubEntity(Client $client)
|
||||||
|
{
|
||||||
|
$entity = false;
|
||||||
|
|
||||||
|
match($this->entity){
|
||||||
|
'invoice' => $entity = Invoice::factory()->make(['client_id' => $client->id,'user_id' => $client->user_id, 'company_id' => $client->company_id]),
|
||||||
|
'quote' => $entity = Quote::factory()->make(['client_id' => $client->id,'user_id' => $client->user_id, 'company_id' => $client->company_id]),
|
||||||
|
'credit' => $entity = Credit::factory()->make(['client_id' => $client->id,'user_id' => $client->user_id, 'company_id' => $client->company_id]),
|
||||||
|
'recurring_invoice' => $entity = RecurringInvoice::factory()->make(['client_id' => $client->id,'user_id' => $client->user_id, 'company_id' => $client->company_id]),
|
||||||
|
default => $entity = Invoice::factory()->make(['client_id' => $client->id,'user_id' => $client->user_id, 'company_id' => $client->company_id]),
|
||||||
|
};
|
||||||
|
|
||||||
|
$entity->setRelation('client', $client);
|
||||||
|
$entity->setRelation('company', $client->company);
|
||||||
|
$entity->setRelation('user', $client->user);
|
||||||
|
$entity->fill($this->all());
|
||||||
|
|
||||||
|
return $entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function convertEntityPlural(string $entity) :self
|
||||||
|
{
|
||||||
|
switch ($entity) {
|
||||||
|
case 'invoice':
|
||||||
|
$this->entity_plural = 'invoices';
|
||||||
|
return $this;
|
||||||
|
case 'quote':
|
||||||
|
$this->entity_plural = 'quotes';
|
||||||
|
return $this;
|
||||||
|
case 'credit':
|
||||||
|
$this->entity_plural = 'credits';
|
||||||
|
return $this;
|
||||||
|
case 'recurring_invoice':
|
||||||
|
$this->entity_plural = 'invoices';
|
||||||
|
return $this;
|
||||||
|
default:
|
||||||
|
$this->entity_plural = 'invoices';
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ class Request extends FormRequest
|
|||||||
use MakesHash;
|
use MakesHash;
|
||||||
use RuntimeFormRequest;
|
use RuntimeFormRequest;
|
||||||
|
|
||||||
protected $file_validation = 'sometimes|file|mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx,webp,xml,zip,csv|max:100000';
|
protected $file_validation = 'sometimes|file|mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx,webp,xml,zip,csv,ods,odt,odp|max:100000';
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
*
|
*
|
||||||
@ -180,7 +180,7 @@ class Request extends FormRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Filter the client contact password - if it is sent with ***** we should ignore it!
|
//Filter the client contact password - if it is sent with ***** we should ignore it!
|
||||||
if (isset($contact['password'])) {
|
if (isset($contact['password']) && is_string($contact['password'])) {
|
||||||
if (strlen($contact['password']) == 0) {
|
if (strlen($contact['password']) == 0) {
|
||||||
$input['contacts'][$key]['password'] = '';
|
$input['contacts'][$key]['password'] = '';
|
||||||
} else {
|
} else {
|
||||||
|
@ -52,7 +52,7 @@ class UpdateTaxData implements ShouldQueue
|
|||||||
{
|
{
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
if($this->company->account->isFreeHostedClient())
|
if($this->company->account->isFreeHostedClient() || $this->client->country_id != 840)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
$tax_provider = new \App\Services\Tax\Providers\TaxProvider($this->company, $this->client);
|
$tax_provider = new \App\Services\Tax\Providers\TaxProvider($this->company, $this->client);
|
||||||
@ -73,69 +73,6 @@ class UpdateTaxData implements ShouldQueue
|
|||||||
nlog("problem getting tax data => ".$e->getMessage());
|
nlog("problem getting tax data => ".$e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if(!$tax_provider->updatedTaxStatus() && $this->client->country_id == 840){
|
|
||||||
|
|
||||||
$calculated_state = false;
|
|
||||||
|
|
||||||
if(array_key_exists($this->client->shipping_state, USStates::get())) {
|
|
||||||
$calculated_state = $this->client->shipping_state;
|
|
||||||
$calculated_postal_code = $this->client->shipping_postal_code;
|
|
||||||
$calculated_city = $this->client->shipping_city;
|
|
||||||
}
|
|
||||||
elseif(array_key_exists($this->client->state, USStates::get())){
|
|
||||||
$calculated_state = $this->client->state;
|
|
||||||
$calculated_postal_code = $this->client->postal_code;
|
|
||||||
$calculated_city = $this->client->city;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
try{
|
|
||||||
$calculated_state = USStates::getState($this->client->shipping_postal_code);
|
|
||||||
$calculated_postal_code = $this->client->shipping_postal_code;
|
|
||||||
$calculated_city = $this->client->shipping_city;
|
|
||||||
}
|
|
||||||
catch(\Exception $e){
|
|
||||||
nlog("could not calculate state from postal code => {$this->client->shipping_postal_code} or from state {$this->client->shipping_state}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!$calculated_state) {
|
|
||||||
try {
|
|
||||||
$calculated_state = USStates::getState($this->client->postal_code);
|
|
||||||
$calculated_postal_code = $this->client->postal_code;
|
|
||||||
$calculated_city = $this->client->city;
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
nlog("could not calculate state from postal code => {$this->client->postal_code} or from state {$this->client->state}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if($this->company->tax_data?->seller_subregion)
|
|
||||||
$calculated_state = $this->company->tax_data?->seller_subregion;
|
|
||||||
|
|
||||||
nlog("i am trying");
|
|
||||||
|
|
||||||
if(!$calculated_state) {
|
|
||||||
nlog("could not determine state");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'seller_subregion' => $this->company->tax_data?->seller_subregion ?: '',
|
|
||||||
'geoPostalCode' => $this->client->postal_code ?? '',
|
|
||||||
'geoCity' => $this->client->city ?? '',
|
|
||||||
'geoState' => $calculated_state,
|
|
||||||
'taxSales' => $this->company->tax_data->regions->US->subregions?->{$calculated_state}?->taxSales ?? 0,
|
|
||||||
];
|
|
||||||
|
|
||||||
$tax_data = new Response($data);
|
|
||||||
|
|
||||||
$this->client->tax_data = $tax_data;
|
|
||||||
$this->client->saveQuietly();
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function middleware()
|
public function middleware()
|
||||||
|
@ -32,12 +32,12 @@ class NinjaMailerObject
|
|||||||
/* Variable for cascading notifications */
|
/* Variable for cascading notifications */
|
||||||
public $entity_string = false;
|
public $entity_string = false;
|
||||||
|
|
||||||
/* @var bool | App\Models\InvoiceInvitation | app\Models\QuoteInvitation | app\Models\CreditInvitation | app\Models\RecurringInvoiceInvitation | app\Models\PurchaseOrderInvitation $invitation*/
|
/* @var bool | App\Models\InvoiceInvitation | App\Models\QuoteInvitation | App\Models\CreditInvitation | App\Models\RecurringInvoiceInvitation | App\Models\PurchaseOrderInvitation $invitation*/
|
||||||
public $invitation = false;
|
public $invitation = false;
|
||||||
|
|
||||||
public $template = false;
|
public $template = false;
|
||||||
|
|
||||||
/* @var bool | App\Models\Invoice | app\Models\Quote | app\Models\Credit | app\Models\RecurringInvoice | app\Models\PurchaseOrder $invitation*/
|
/* @var bool | App\Models\Invoice | App\Models\Quote | App\Models\Credit | App\Models\RecurringInvoice | App\Models\PurchaseOrder | App\Models\Payment $entity */
|
||||||
public $entity = false;
|
public $entity = false;
|
||||||
|
|
||||||
public $reminder_template = '';
|
public $reminder_template = '';
|
||||||
|
@ -83,11 +83,21 @@ class EmailPayment implements ShouldQueue
|
|||||||
|
|
||||||
$invitation = null;
|
$invitation = null;
|
||||||
|
|
||||||
|
$nmo = new NinjaMailerObject;
|
||||||
|
|
||||||
if ($this->payment->invoices && $this->payment->invoices->count() >= 1) {
|
if ($this->payment->invoices && $this->payment->invoices->count() >= 1) {
|
||||||
$invitation = $this->payment->invoices->first()->invitations()->first();
|
|
||||||
|
if($this->contact){
|
||||||
|
$invitation = $this->payment->invoices->first()->invitations()->where('client_contact_id', $this->contact->id)->first();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$invitation = $this->payment->invoices->first()->invitations()->first();
|
||||||
|
|
||||||
|
if($invitation)
|
||||||
|
$nmo->invitation = $invitation;
|
||||||
}
|
}
|
||||||
|
|
||||||
$nmo = new NinjaMailerObject;
|
|
||||||
$nmo->mailable = new TemplateEmail($email_builder, $this->contact, $invitation);
|
$nmo->mailable = new TemplateEmail($email_builder, $this->contact, $invitation);
|
||||||
$nmo->to_user = $this->contact;
|
$nmo->to_user = $this->contact;
|
||||||
$nmo->settings = $this->settings;
|
$nmo->settings = $this->settings;
|
||||||
|
@ -88,11 +88,22 @@ class EmailRefundPayment implements ShouldQueue
|
|||||||
|
|
||||||
$invitation = null;
|
$invitation = null;
|
||||||
|
|
||||||
|
$nmo = new NinjaMailerObject;
|
||||||
|
|
||||||
if ($this->payment->invoices && $this->payment->invoices->count() >= 1) {
|
if ($this->payment->invoices && $this->payment->invoices->count() >= 1) {
|
||||||
$invitation = $this->payment->invoices->first()->invitations()->first();
|
|
||||||
|
if($this->contact) {
|
||||||
|
$invitation = $this->payment->invoices->first()->invitations()->where('client_contact_id', $this->contact->id)->first();
|
||||||
|
} else {
|
||||||
|
$invitation = $this->payment->invoices->first()->invitations()->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
if($invitation)
|
||||||
|
$nmo->invitation = $invitation;
|
||||||
}
|
}
|
||||||
|
|
||||||
$nmo = new NinjaMailerObject;
|
|
||||||
|
|
||||||
$nmo->mailable = new TemplateEmail($email_builder, $this->contact, $invitation);
|
$nmo->mailable = new TemplateEmail($email_builder, $this->contact, $invitation);
|
||||||
$nmo->to_user = $this->contact;
|
$nmo->to_user = $this->contact;
|
||||||
$nmo->settings = $this->settings;
|
$nmo->settings = $this->settings;
|
||||||
|
@ -56,6 +56,23 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getSystemLog(string $message_id): ?SystemLog
|
||||||
|
{
|
||||||
|
return SystemLog::query()
|
||||||
|
->where('company_id', $this->invitation->company_id)
|
||||||
|
->where('type_id', SystemLog::TYPE_WEBHOOK_RESPONSE)
|
||||||
|
->whereJsonContains('log', ['MessageID' => $message_id])
|
||||||
|
->orderBy('id','desc')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function updateSystemLog(SystemLog $system_log, array $data): void
|
||||||
|
{
|
||||||
|
$system_log->log = $data;
|
||||||
|
$system_log->save();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the job.
|
* Execute the job.
|
||||||
*
|
*
|
||||||
@ -135,6 +152,13 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
|
|
||||||
$data = array_merge($this->request, ['history' => $this->fetchMessage()]);
|
$data = array_merge($this->request, ['history' => $this->fetchMessage()]);
|
||||||
|
|
||||||
|
$sl = $this->getSystemLog($this->request['MessageID']);
|
||||||
|
|
||||||
|
if($sl){
|
||||||
|
$this->updateSystemLog($sl, $data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
(new SystemLogger(
|
(new SystemLogger(
|
||||||
$data,
|
$data,
|
||||||
SystemLog::CATEGORY_MAIL,
|
SystemLog::CATEGORY_MAIL,
|
||||||
@ -166,6 +190,13 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
|
|
||||||
$data = array_merge($this->request, ['history' => $this->fetchMessage()]);
|
$data = array_merge($this->request, ['history' => $this->fetchMessage()]);
|
||||||
|
|
||||||
|
$sl = $this->getSystemLog($this->request['MessageID']);
|
||||||
|
|
||||||
|
if($sl) {
|
||||||
|
$this->updateSystemLog($sl, $data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
(new SystemLogger(
|
(new SystemLogger(
|
||||||
$data,
|
$data,
|
||||||
SystemLog::CATEGORY_MAIL,
|
SystemLog::CATEGORY_MAIL,
|
||||||
@ -217,6 +248,13 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
|
|
||||||
$data = array_merge($this->request, ['history' => $this->fetchMessage()]);
|
$data = array_merge($this->request, ['history' => $this->fetchMessage()]);
|
||||||
|
|
||||||
|
$sl = $this->getSystemLog($this->request['MessageID']);
|
||||||
|
|
||||||
|
if($sl) {
|
||||||
|
$this->updateSystemLog($sl, $data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
(new SystemLogger($data, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company))->handle();
|
(new SystemLogger($data, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company))->handle();
|
||||||
|
|
||||||
// if(config('ninja.notification.slack'))
|
// if(config('ninja.notification.slack'))
|
||||||
@ -263,6 +301,13 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
|
|
||||||
$data = array_merge($this->request, ['history' => $this->fetchMessage()]);
|
$data = array_merge($this->request, ['history' => $this->fetchMessage()]);
|
||||||
|
|
||||||
|
$sl = $this->getSystemLog($this->request['MessageID']);
|
||||||
|
|
||||||
|
if($sl) {
|
||||||
|
$this->updateSystemLog($sl, $data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
(new SystemLogger($data, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_SPAM_COMPLAINT, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company))->handle();
|
(new SystemLogger($data, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_SPAM_COMPLAINT, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company))->handle();
|
||||||
|
|
||||||
if (config('ninja.notification.slack')) {
|
if (config('ninja.notification.slack')) {
|
||||||
@ -294,6 +339,32 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRawMessage(string $message_id)
|
||||||
|
{
|
||||||
|
|
||||||
|
$postmark = new PostmarkClient(config('services.postmark.token'));
|
||||||
|
$messageDetail = $postmark->getOutboundMessageDetails($message_id);
|
||||||
|
return $messageDetail;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getBounceId(string $message_id): ?int
|
||||||
|
{
|
||||||
|
|
||||||
|
$messageDetail = $this->getRawMessage($message_id);
|
||||||
|
|
||||||
|
|
||||||
|
$event = collect($messageDetail->messageevents)->first(function ($event) {
|
||||||
|
|
||||||
|
return $event?->Details?->BounceID ?? false;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return $event?->Details?->BounceID ?? null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private function fetchMessage(): array
|
private function fetchMessage(): array
|
||||||
{
|
{
|
||||||
if(strlen($this->request['MessageID']) < 1){
|
if(strlen($this->request['MessageID']) < 1){
|
||||||
@ -311,6 +382,7 @@ class ProcessPostmarkWebhook implements ShouldQueue
|
|||||||
$events = collect($messageDetail->messageevents)->map(function ($event) {
|
$events = collect($messageDetail->messageevents)->map(function ($event) {
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
'bounce_id' => $event?->Details?->BounceID ?? '',
|
||||||
'recipient' => $event->Recipient ?? '',
|
'recipient' => $event->Recipient ?? '',
|
||||||
'status' => $event->Type ?? '',
|
'status' => $event->Type ?? '',
|
||||||
'delivery_message' => $event->Details->DeliveryMessage ?? $event->Details->Summary ?? '',
|
'delivery_message' => $event->Details->DeliveryMessage ?? $event->Details->Summary ?? '',
|
||||||
|
@ -24,25 +24,14 @@ class PreviewPdf implements ShouldQueue
|
|||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, PdfMaker, PageNumbering;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, PdfMaker, PageNumbering;
|
||||||
|
|
||||||
public $company;
|
|
||||||
|
|
||||||
private $disk;
|
|
||||||
|
|
||||||
public $design_string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new job instance.
|
* Create a new job instance.
|
||||||
*
|
*
|
||||||
* @param $design_string
|
* @param $design_string
|
||||||
* @param Company $company
|
* @param Company $company
|
||||||
*/
|
*/
|
||||||
public function __construct($design_string, Company $company)
|
public function __construct(public string $design_string, public Company $company)
|
||||||
{
|
{
|
||||||
$this->company = $company;
|
|
||||||
|
|
||||||
$this->design_string = $design_string;
|
|
||||||
|
|
||||||
$this->disk = $disk ?? config('filesystems.default');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
|
@ -41,6 +41,7 @@ class MailSentListener implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle(MessageSent $event)
|
public function handle(MessageSent $event)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!Ninja::isHosted()) {
|
if (!Ninja::isHosted()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ class UpdateUserLastLogin implements ShouldQueue
|
|||||||
$key = "user_logged_in_{$user->id}{$event->company->db}";
|
$key = "user_logged_in_{$user->id}{$event->company->db}";
|
||||||
|
|
||||||
|
|
||||||
if ($user->ip != $ip && is_null(Cache::get($key))) {
|
if ($user->ip != $ip && is_null(Cache::get($key)) && $user->user_logged_in_notification) {
|
||||||
$nmo = new NinjaMailerObject;
|
$nmo = new NinjaMailerObject;
|
||||||
$nmo->mailable = new UserLoggedIn($user, $user->account->companies->first(), $ip);
|
$nmo->mailable = new UserLoggedIn($user, $user->account->companies->first(), $ip);
|
||||||
$nmo->company = $user->account->companies->first();
|
$nmo->company = $user->account->companies->first();
|
||||||
@ -69,6 +69,7 @@ class UpdateUserLastLogin implements ShouldQueue
|
|||||||
|
|
||||||
Cache::put($key, true, 60 * 24);
|
Cache::put($key, true, 60 * 24);
|
||||||
$arr = json_encode(['ip' => $ip]);
|
$arr = json_encode(['ip' => $ip]);
|
||||||
|
$arr = ctrans('texts.new_login_detected'). " {$ip}";
|
||||||
|
|
||||||
SystemLogger::dispatch(
|
SystemLogger::dispatch(
|
||||||
$arr,
|
$arr,
|
||||||
|
@ -108,12 +108,15 @@ class TemplateEmail extends Mailable
|
|||||||
|
|
||||||
if (strlen($settings->bcc_email) > 1) {
|
if (strlen($settings->bcc_email) > 1) {
|
||||||
if (Ninja::isHosted()) {
|
if (Ninja::isHosted()) {
|
||||||
$bccs = explode(',', str_replace(' ', '', $settings->bcc_email));
|
|
||||||
$this->bcc(array_slice($bccs, 0, 2));
|
if($company->account->isPaid()) {
|
||||||
//$this->bcc(reset($bccs)); //remove whitespace if any has been inserted.
|
$bccs = explode(',', str_replace(' ', '', $settings->bcc_email));
|
||||||
|
$this->bcc(array_slice($bccs, 0, 5));
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$this->bcc(explode(',', str_replace(' ', '', $settings->bcc_email)));
|
$this->bcc(explode(',', str_replace(' ', '', $settings->bcc_email)));
|
||||||
}//remove whitespace if any has been inserted.
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->subject(str_replace("<br>", "", $this->build_email->getSubject()))
|
$this->subject(str_replace("<br>", "", $this->build_email->getSubject()))
|
||||||
|
@ -17,7 +17,6 @@ use Illuminate\Queue\SerializesModels;
|
|||||||
|
|
||||||
class TestMailServer extends Mailable
|
class TestMailServer extends Mailable
|
||||||
{
|
{
|
||||||
// use Queueable, SerializesModels;
|
|
||||||
|
|
||||||
public $support_messages;
|
public $support_messages;
|
||||||
|
|
||||||
|
@ -11,10 +11,11 @@
|
|||||||
|
|
||||||
namespace App\Mail;
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use App\Utils\Ninja;
|
||||||
use App\Models\VendorContact;
|
use App\Models\VendorContact;
|
||||||
use App\Services\PdfMaker\Designs\Utilities\DesignHelpers;
|
|
||||||
use App\Utils\VendorHtmlEngine;
|
|
||||||
use Illuminate\Mail\Mailable;
|
use Illuminate\Mail\Mailable;
|
||||||
|
use App\Utils\VendorHtmlEngine;
|
||||||
|
use App\Services\PdfMaker\Designs\Utilities\DesignHelpers;
|
||||||
|
|
||||||
class VendorTemplateEmail extends Mailable
|
class VendorTemplateEmail extends Mailable
|
||||||
{
|
{
|
||||||
@ -102,8 +103,19 @@ class VendorTemplateEmail extends Mailable
|
|||||||
$this->from(config('mail.from.address'), $email_from_name);
|
$this->from(config('mail.from.address'), $email_from_name);
|
||||||
|
|
||||||
if (strlen($settings->bcc_email) > 1) {
|
if (strlen($settings->bcc_email) > 1) {
|
||||||
$this->bcc(explode(',', str_replace(' ', '', $settings->bcc_email)));
|
|
||||||
}//remove whitespace if any has been inserted.
|
if (Ninja::isHosted()) {
|
||||||
|
|
||||||
|
if($this->company->account->isPaid()) {
|
||||||
|
$bccs = explode(',', str_replace(' ', '', $settings->bcc_email));
|
||||||
|
$this->bcc(array_slice($bccs, 0, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$this->bcc(explode(',', str_replace(' ', '', $settings->bcc_email)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
$this->subject($this->build_email->getSubject())
|
$this->subject($this->build_email->getSubject())
|
||||||
->text('email.template.text', [
|
->text('email.template.text', [
|
||||||
|
@ -306,7 +306,7 @@ class Client extends BaseModel implements HasLocalePreference
|
|||||||
return $this->hasMany(ClientContact::class)->where('is_primary', true);
|
return $this->hasMany(ClientContact::class)->where('is_primary', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function company() :BelongsTo
|
public function company(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Company::class);
|
return $this->belongsTo(Company::class);
|
||||||
}
|
}
|
||||||
|
@ -786,6 +786,26 @@ class Company extends BaseModel
|
|||||||
return $this->hasMany(CompanyUser::class)->withTrashed();
|
return $this->hasMany(CompanyUser::class)->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function invoice_invitations(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(InvoiceInvitation::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function quote_invitations(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(QuoteInvitation::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function credit_invitations(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(CreditInvitation::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function purchase_order_invitations(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(PurchaseOrderInvitation::class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \App\Models\User|null
|
* @return \App\Models\User|null
|
||||||
*/
|
*/
|
||||||
|
@ -23,7 +23,7 @@ class ClientPresenter extends EntityPresenter
|
|||||||
*/
|
*/
|
||||||
public function name()
|
public function name()
|
||||||
{
|
{
|
||||||
if ($this->entity->name) {
|
if (strlen($this->entity->name) > 1) {
|
||||||
return $this->entity->name;
|
return $this->entity->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,8 @@ use Illuminate\Foundation\Auth\User as Authenticatable;
|
|||||||
* @property int|null $deleted_at
|
* @property int|null $deleted_at
|
||||||
* @property string|null $oauth_user_refresh_token
|
* @property string|null $oauth_user_refresh_token
|
||||||
* @property string|null $last_confirmed_email_address
|
* @property string|null $last_confirmed_email_address
|
||||||
* @property int $has_password
|
* @property bool $has_password
|
||||||
|
* @property bool $user_logged_in_notification
|
||||||
* @property Carbon|null $oauth_user_token_expiry
|
* @property Carbon|null $oauth_user_token_expiry
|
||||||
* @property string|null $sms_verification_code
|
* @property string|null $sms_verification_code
|
||||||
* @property bool $verified_phone_number
|
* @property bool $verified_phone_number
|
||||||
@ -140,6 +141,7 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
|
'user_logged_in_notification',
|
||||||
'first_name',
|
'first_name',
|
||||||
'last_name',
|
'last_name',
|
||||||
'email',
|
'email',
|
||||||
|
@ -251,7 +251,7 @@ class CreditCard
|
|||||||
|
|
||||||
$response = $this->eway_driver->init()->eway->createTransaction(\Eway\Rapid\Enum\ApiMethod::DIRECT, $transaction);
|
$response = $this->eway_driver->init()->eway->createTransaction(\Eway\Rapid\Enum\ApiMethod::DIRECT, $transaction);
|
||||||
|
|
||||||
if ($response->TransactionStatus) {
|
if ($response->TransactionStatus ?? false) {
|
||||||
$this->logResponse($response, true);
|
$this->logResponse($response, true);
|
||||||
$payment = $this->storePayment($response);
|
$payment = $this->storePayment($response);
|
||||||
} else {
|
} else {
|
||||||
|
@ -183,7 +183,7 @@ class CreditCard
|
|||||||
|
|
||||||
$response = $this->paytrace->gatewayRequest('/v1/transactions/sale/by_customer', $data);
|
$response = $this->paytrace->gatewayRequest('/v1/transactions/sale/by_customer', $data);
|
||||||
|
|
||||||
if ($response->success) {
|
if ($response->success ?? false) {
|
||||||
$this->paytrace->logSuccessfulGatewayResponse(['response' => $response, 'data' => $this->paytrace->payment_hash], SystemLog::TYPE_PAYTRACE);
|
$this->paytrace->logSuccessfulGatewayResponse(['response' => $response, 'data' => $this->paytrace->payment_hash], SystemLog::TYPE_PAYTRACE);
|
||||||
|
|
||||||
return $this->processSuccessfulPayment($response);
|
return $this->processSuccessfulPayment($response);
|
||||||
|
@ -198,7 +198,7 @@ class PaytracePaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
$auth_data = json_decode($response);
|
$auth_data = json_decode($response);
|
||||||
|
|
||||||
if (! property_exists($auth_data, 'access_token')) {
|
if (!isset($auth_data) || ! property_exists($auth_data, 'access_token')) {
|
||||||
throw new SystemError('Error authenticating with PayTrace');
|
throw new SystemError('Error authenticating with PayTrace');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,8 +134,8 @@ class SquareWebhook implements ShouldQueue
|
|||||||
|
|
||||||
nlog("Searching by payment hash");
|
nlog("Searching by payment hash");
|
||||||
|
|
||||||
$payment_hash_id = $apiResponse->getPayment()->getReferenceId() ?? false;
|
$payment_hash_id = $apiResponse->getResult()->getPayment()->getReferenceId() ?? false;
|
||||||
$square_payment = $apiResponse->getPayment()->jsonSerialize();
|
$square_payment = $apiResponse->getResult()->getPayment()->jsonSerialize();
|
||||||
$payment_hash = PaymentHash::query()->where('hash', $payment_hash_id)->firstOrFail();
|
$payment_hash = PaymentHash::query()->where('hash', $payment_hash_id)->firstOrFail();
|
||||||
|
|
||||||
$payment_hash->data = array_merge((array) $payment_hash->data, (array)$square_payment);
|
$payment_hash->data = array_merge((array) $payment_hash->data, (array)$square_payment);
|
||||||
|
@ -140,7 +140,7 @@ class Email implements ShouldQueue
|
|||||||
|
|
||||||
$this->email_object->client_id ? $this->email_object->settings = $this->email_object->client->getMergedSettings() : $this->email_object->settings = $this->company->settings;
|
$this->email_object->client_id ? $this->email_object->settings = $this->email_object->client->getMergedSettings() : $this->email_object->settings = $this->company->settings;
|
||||||
|
|
||||||
$this->email_object->client_id ? nlog("client settings") : nlog("company settings ");
|
// $this->email_object->client_id ? nlog("client settings") : nlog("company settings ");
|
||||||
|
|
||||||
$this->email_object->whitelabel = $this->company->account->isPaid() ? true : false;
|
$this->email_object->whitelabel = $this->company->account->isPaid() ? true : false;
|
||||||
|
|
||||||
@ -413,6 +413,14 @@ class Email implements ShouldQueue
|
|||||||
if ($address_object->address == " ") {
|
if ($address_object->address == " ") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($address_object->address == "") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($address_object->name == " " || $address_object->name == "") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -255,8 +255,8 @@ class EmailDefaults
|
|||||||
|
|
||||||
if (strlen($this->email->email_object->settings->bcc_email) > 1) {
|
if (strlen($this->email->email_object->settings->bcc_email) > 1) {
|
||||||
if (Ninja::isHosted() && $this->email->company->account->isPaid()) {
|
if (Ninja::isHosted() && $this->email->company->account->isPaid()) {
|
||||||
$bccs = array_slice(explode(',', str_replace(' ', '', $this->email->email_object->settings->bcc_email)), 0, 2);
|
$bccs = array_slice(explode(',', str_replace(' ', '', $this->email->email_object->settings->bcc_email)), 0, 5);
|
||||||
} elseif (Ninja::isSelfHost()) {
|
} else {
|
||||||
$bccs = (explode(',', str_replace(' ', '', $this->email->email_object->settings->bcc_email)));
|
$bccs = (explode(',', str_replace(' ', '', $this->email->email_object->settings->bcc_email)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ class AutoBillInvoice extends AbstractService
|
|||||||
/* Build payment hash */
|
/* Build payment hash */
|
||||||
|
|
||||||
$payment_hash = PaymentHash::create([
|
$payment_hash = PaymentHash::create([
|
||||||
'hash' => Str::random(64),
|
'hash' => Str::random(32),
|
||||||
'data' => [
|
'data' => [
|
||||||
'amount_with_fee' => $amount + $fee,
|
'amount_with_fee' => $amount + $fee,
|
||||||
'invoices' => [
|
'invoices' => [
|
||||||
|
@ -75,7 +75,7 @@ class ZugferdEInvoice extends AbstractService
|
|||||||
} else {
|
} else {
|
||||||
$this->xrechnung->setDocumentBuyerReference($client->routing_id);
|
$this->xrechnung->setDocumentBuyerReference($client->routing_id);
|
||||||
}
|
}
|
||||||
if (!empty($client->shipping_address1)){
|
if (!empty($client->shipping_address1) && $client->shipping_country->exists()){
|
||||||
$this->xrechnung->setDocumentShipToAddress($client->shipping_address1, $client->shipping_address2, "", $client->shipping_postal_code, $client->shipping_city, $client->shipping_country->iso_3166_2, $client->shipping_state);
|
$this->xrechnung->setDocumentShipToAddress($client->shipping_address1, $client->shipping_address2, "", $client->shipping_postal_code, $client->shipping_city, $client->shipping_country->iso_3166_2, $client->shipping_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,11 @@ class DeletePayment
|
|||||||
|
|
||||||
if ($paymentable_invoice->balance == $paymentable_invoice->amount) {
|
if ($paymentable_invoice->balance == $paymentable_invoice->amount) {
|
||||||
$paymentable_invoice->service()->setStatus(Invoice::STATUS_SENT)->save();
|
$paymentable_invoice->service()->setStatus(Invoice::STATUS_SENT)->save();
|
||||||
} else {
|
}
|
||||||
|
elseif($paymentable_invoice->balance == 0){
|
||||||
|
$paymentable_invoice->service()->setStatus(Invoice::STATUS_PAID)->save();
|
||||||
|
}
|
||||||
|
else {
|
||||||
$paymentable_invoice->service()->setStatus(Invoice::STATUS_PARTIAL)->save();
|
$paymentable_invoice->service()->setStatus(Invoice::STATUS_PARTIAL)->save();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -225,6 +225,8 @@ class TaxProvider
|
|||||||
*/
|
*/
|
||||||
private function configureEuTax(): self
|
private function configureEuTax(): self
|
||||||
{
|
{
|
||||||
|
throw new \Exception("No tax region defined for this country");
|
||||||
|
|
||||||
$this->provider = EuTax::class;
|
$this->provider = EuTax::class;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -17,6 +17,7 @@ use App\Models\ClientContact;
|
|||||||
use App\Models\ClientGatewayToken;
|
use App\Models\ClientGatewayToken;
|
||||||
use App\Models\CompanyLedger;
|
use App\Models\CompanyLedger;
|
||||||
use App\Models\Document;
|
use App\Models\Document;
|
||||||
|
use App\Models\GroupSetting;
|
||||||
use App\Models\SystemLog;
|
use App\Models\SystemLog;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use League\Fractal\Resource\Collection;
|
use League\Fractal\Resource\Collection;
|
||||||
@ -42,6 +43,7 @@ class ClientTransformer extends EntityTransformer
|
|||||||
'activities',
|
'activities',
|
||||||
'ledger',
|
'ledger',
|
||||||
'system_logs',
|
'system_logs',
|
||||||
|
'group_settings',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -96,6 +98,16 @@ class ClientTransformer extends EntityTransformer
|
|||||||
return $this->includeCollection($client->system_logs, $transformer, SystemLog::class);
|
return $this->includeCollection($client->system_logs, $transformer, SystemLog::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function includeGroupSettings(Client $client)
|
||||||
|
{
|
||||||
|
if (!$client->group_settings)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
$transformer = new GroupSettingTransformer($this->serializer);
|
||||||
|
|
||||||
|
return $this->includeItem($client->group_settings, $transformer, GroupSetting::class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Client $client
|
* @param Client $client
|
||||||
*
|
*
|
||||||
|
@ -33,6 +33,7 @@ class CreditInvitationTransformer extends EntityTransformer
|
|||||||
'created_at' => (int) $invitation->created_at,
|
'created_at' => (int) $invitation->created_at,
|
||||||
'email_status' => $invitation->email_status ?: '',
|
'email_status' => $invitation->email_status ?: '',
|
||||||
'email_error' => (string) $invitation->email_error,
|
'email_error' => (string) $invitation->email_error,
|
||||||
|
'message_id' => (string) $invitation->message_id ?: '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ class InvoiceInvitationTransformer extends EntityTransformer
|
|||||||
'created_at' => (int) $invitation->created_at,
|
'created_at' => (int) $invitation->created_at,
|
||||||
'email_status' => $invitation->email_status ?: '',
|
'email_status' => $invitation->email_status ?: '',
|
||||||
'email_error' => (string) $invitation->email_error,
|
'email_error' => (string) $invitation->email_error,
|
||||||
|
'message_id' => (string) $invitation->message_id ?: '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ class PurchaseOrderInvitationTransformer extends EntityTransformer
|
|||||||
'created_at' => (int) $invitation->created_at,
|
'created_at' => (int) $invitation->created_at,
|
||||||
'email_status' => $invitation->email_status ?: '',
|
'email_status' => $invitation->email_status ?: '',
|
||||||
'email_error' => (string) $invitation->email_error,
|
'email_error' => (string) $invitation->email_error,
|
||||||
|
'message_id' => (string) $invitation->message_id ?: '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ class QuoteInvitationTransformer extends EntityTransformer
|
|||||||
'created_at' => (int) $invitation->created_at,
|
'created_at' => (int) $invitation->created_at,
|
||||||
'email_status' => $invitation->email_status ?: '',
|
'email_status' => $invitation->email_status ?: '',
|
||||||
'email_error' => (string) $invitation->email_error,
|
'email_error' => (string) $invitation->email_error,
|
||||||
|
'message_id' => (string) $invitation->message_id ?: '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ class RecurringInvoiceInvitationTransformer extends EntityTransformer
|
|||||||
'created_at' => (int) $invitation->created_at,
|
'created_at' => (int) $invitation->created_at,
|
||||||
'email_status' => $invitation->email_status ?: '',
|
'email_status' => $invitation->email_status ?: '',
|
||||||
'email_error' => (string) $invitation->email_error,
|
'email_error' => (string) $invitation->email_error,
|
||||||
|
'message_id' => (string) $invitation->message_id ?: '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,7 @@ class UserTransformer extends EntityTransformer
|
|||||||
'oauth_user_token' => empty($user->oauth_user_token) ? '' : '***',
|
'oauth_user_token' => empty($user->oauth_user_token) ? '' : '***',
|
||||||
'verified_phone_number' => (bool) $user->verified_phone_number,
|
'verified_phone_number' => (bool) $user->verified_phone_number,
|
||||||
'language_id' => (string) $user->language_id ?? '',
|
'language_id' => (string) $user->language_id ?? '',
|
||||||
|
'user_logged_in_notification' => (bool) $user->user_logged_in_notification,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -670,16 +670,16 @@ class HtmlEngine
|
|||||||
$data['$payment.transaction_reference'] = ['value' => '', 'label' => ctrans('texts.transaction_reference')];
|
$data['$payment.transaction_reference'] = ['value' => '', 'label' => ctrans('texts.transaction_reference')];
|
||||||
|
|
||||||
|
|
||||||
if ($this->entity_string == 'invoice' && $this->entity->payments()->exists()) {
|
if ($this->entity_string == 'invoice' && $this->entity->net_payments()->exists()) {
|
||||||
$payment_list = '<br><br>';
|
$payment_list = '<br><br>';
|
||||||
|
|
||||||
foreach ($this->entity->payments as $payment) {
|
foreach ($this->entity->net_payments as $payment) {
|
||||||
$payment_list .= ctrans('texts.payment_subject') . ": " . $this->formatDate($payment->date, $this->client->date_format()) . " :: " . Number::formatMoney($payment->amount, $this->client) ." :: ". GatewayType::getAlias($payment->gateway_type_id) . "<br>";
|
$payment_list .= ctrans('texts.payment_subject') . ": " . $this->formatDate($payment->date, $this->client->date_format()) . " :: " . Number::formatMoney($payment->amount, $this->client) ." :: ". GatewayType::getAlias($payment->gateway_type_id) . "<br>";
|
||||||
}
|
}
|
||||||
|
|
||||||
$data['$payments'] = ['value' => $payment_list, 'label' => ctrans('texts.payments')];
|
$data['$payments'] = ['value' => $payment_list, 'label' => ctrans('texts.payments')];
|
||||||
|
|
||||||
$payment = $this->entity->payments()->first();
|
$payment = $this->entity->net_payments()->first();
|
||||||
|
|
||||||
$data['$payment.custom1'] = ['value' => $payment->custom_value1, 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'payment1')];
|
$data['$payment.custom1'] = ['value' => $payment->custom_value1, 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'payment1')];
|
||||||
$data['$payment.custom2'] = ['value' => $payment->custom_value2, 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'payment2')];
|
$data['$payment.custom2'] = ['value' => $payment->custom_value2, 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'payment2')];
|
||||||
@ -1014,17 +1014,17 @@ html {
|
|||||||
*/
|
*/
|
||||||
protected function generateEntityImagesMarkup()
|
protected function generateEntityImagesMarkup()
|
||||||
{
|
{
|
||||||
// if (!$this->client->getSetting('embed_documents') && !$this->company->account->hasFeature(Account::FEATURE_DOCUMENTS)) {
|
if (!$this->client->getSetting('embed_documents') || !$this->company->account->hasFeature(Account::FEATURE_DOCUMENTS)) {
|
||||||
// return '';
|
return '';
|
||||||
// }
|
}
|
||||||
|
|
||||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||||
|
|
||||||
$container = $dom->createElement('div');
|
$container = $dom->createElement('div');
|
||||||
$container->setAttribute('style', 'display:grid; grid-auto-flow: row; grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(2, 1fr);justify-items: center;');
|
$container->setAttribute('style', 'display:grid; grid-auto-flow: row; grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(2, 1fr);justify-items: center;');
|
||||||
|
|
||||||
foreach ($this->entity->documents as $document) {
|
foreach ($this->entity->documents()->where('is_public',true)->get() as $document) {
|
||||||
if (!$document->isImage()) {
|
if (!$document->isImage()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,8 +62,27 @@ trait MakesHash
|
|||||||
return $hashids->encode($value);
|
return $hashids->encode($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function decodePrimaryKey($value)
|
public function decodePrimaryKey($value, $return_string_failure = false)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
try {
|
||||||
|
$hashids = new Hashids(config('ninja.hash_salt'), 10);
|
||||||
|
|
||||||
|
$decoded_array = $hashids->decode($value);
|
||||||
|
|
||||||
|
if(isset($decoded_array[0]) ?? false) {
|
||||||
|
return $decoded_array[0];
|
||||||
|
} elseif($return_string_failure) {
|
||||||
|
return "Invalid Primary Key";
|
||||||
|
} else {
|
||||||
|
throw new \Exception('Invalid Primary Key');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return response()->json(['error'=>'Invalid primary key'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
try {
|
try {
|
||||||
$hashids = new Hashids(config('ninja.hash_salt'), 10);
|
$hashids = new Hashids(config('ninja.hash_salt'), 10);
|
||||||
|
|
||||||
@ -77,6 +96,7 @@ trait MakesHash
|
|||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return response()->json(['error'=>'Invalid primary key'], 400);
|
return response()->json(['error'=>'Invalid primary key'], 400);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public function transformKeys($keys)
|
public function transformKeys($keys)
|
||||||
|
@ -12,18 +12,19 @@
|
|||||||
|
|
||||||
namespace App\Utils;
|
namespace App\Utils;
|
||||||
|
|
||||||
use App\Models\Country;
|
|
||||||
use App\Models\CreditInvitation;
|
|
||||||
use App\Models\InvoiceInvitation;
|
|
||||||
use App\Models\PurchaseOrderInvitation;
|
|
||||||
use App\Models\QuoteInvitation;
|
|
||||||
use App\Models\RecurringInvoiceInvitation;
|
|
||||||
use App\Utils\Traits\AppSetup;
|
|
||||||
use App\Utils\Traits\DesignCalculator;
|
|
||||||
use App\Utils\Traits\MakesDates;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Models\Country;
|
||||||
|
use App\Utils\Traits\AppSetup;
|
||||||
|
use App\Models\QuoteInvitation;
|
||||||
|
use App\Models\CreditInvitation;
|
||||||
|
use App\Utils\Traits\MakesDates;
|
||||||
|
use App\Models\InvoiceInvitation;
|
||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use App\Utils\Traits\DesignCalculator;
|
||||||
|
use App\Models\PurchaseOrderInvitation;
|
||||||
|
use App\Models\RecurringInvoiceInvitation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note the premise used here is that any currencies will be formatted back to the company currency and not
|
* Note the premise used here is that any currencies will be formatted back to the company currency and not
|
||||||
@ -775,31 +776,37 @@ html {
|
|||||||
*/
|
*/
|
||||||
protected function generateEntityImagesMarkup()
|
protected function generateEntityImagesMarkup()
|
||||||
{
|
{
|
||||||
if ($this->company->getSetting('embed_documents') === false) {
|
|
||||||
|
if (!$this->vendor->getSetting('embed_documents') || !$this->company->account->hasFeature(Account::FEATURE_DOCUMENTS)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||||
|
|
||||||
$container = $dom->createElement('div');
|
$container = $dom->createElement('div');
|
||||||
$container->setAttribute('style', 'display:grid; grid-auto-flow: row; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(2, 1fr);');
|
$container->setAttribute('style', 'display:grid; grid-auto-flow: row; grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(2, 1fr);justify-items: center;');
|
||||||
|
|
||||||
foreach ($this->entity->documents as $document) {
|
foreach ($this->entity->documents()->where('is_public',true)->get() as $document) {
|
||||||
if (!$document->isImage()) {
|
if (!$document->isImage()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$image = $dom->createElement('img');
|
$image = $dom->createElement('img');
|
||||||
|
|
||||||
$image->setAttribute('src', $document->generateUrl());
|
$image->setAttribute('src', "data:image/png;base64,".base64_encode($document->getFile()));
|
||||||
$image->setAttribute('style', 'max-height: 100px; margin-top: 20px;');
|
$image->setAttribute('style', 'max-width: 50%; margin-top: 20px;');
|
||||||
|
|
||||||
$container->appendChild($image);
|
$container->appendChild($image);
|
||||||
}
|
}
|
||||||
|
|
||||||
$dom->appendChild($container);
|
$dom->appendChild($container);
|
||||||
|
|
||||||
return $dom->saveHTML();
|
$html = $dom->saveHTML();
|
||||||
|
|
||||||
|
$dom = null;
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,8 +15,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' => env('APP_VERSION','5.7.30'),
|
'app_version' => env('APP_VERSION','5.7.33'),
|
||||||
'app_tag' => env('APP_TAG','5.7.30'),
|
'app_tag' => env('APP_TAG','5.7.33'),
|
||||||
'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', ''),
|
||||||
|
30
database/factories/RecurringInvoiceInvitationFactory.php
Normal file
30
database/factories/RecurringInvoiceInvitationFactory.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class RecurringInvoiceInvitationFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function definition()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'key' => Str::random(40),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Currency;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->boolean('user_logged_in_notification')->default(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$cur = Currency::find(120);
|
||||||
|
|
||||||
|
if(!$cur) {
|
||||||
|
$cur = new \App\Models\Currency();
|
||||||
|
$cur->id = 120;
|
||||||
|
$cur->code = 'TOP';
|
||||||
|
$cur->name = "Tongan Pa'anga";
|
||||||
|
$cur->symbol = 'T$';
|
||||||
|
$cur->thousand_separator = ',';
|
||||||
|
$cur->decimal_separator = '.';
|
||||||
|
$cur->precision = 2;
|
||||||
|
$cur->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
};
|
@ -142,6 +142,7 @@ class CurrenciesSeeder extends Seeder
|
|||||||
['id' => 117, 'name' => 'Gold Troy Ounce', 'code' => 'XAU', 'symbol' => 'XAU', 'precision' => '3', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
['id' => 117, 'name' => 'Gold Troy Ounce', 'code' => 'XAU', 'symbol' => 'XAU', 'precision' => '3', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||||
['id' => 118, 'name' => 'Nicaraguan Córdoba', 'code' => 'NIO', 'symbol' => 'C$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
['id' => 118, 'name' => 'Nicaraguan Córdoba', 'code' => 'NIO', 'symbol' => 'C$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||||
['id' => 119, 'name' => 'Malagasy ariary', 'code' => 'MGA', 'symbol' => 'Ar', 'precision' => '0', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
['id' => 119, 'name' => 'Malagasy ariary', 'code' => 'MGA', 'symbol' => 'Ar', 'precision' => '0', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||||
|
['id' => 120, 'name' => "Tongan Pa anga", 'code' => 'TOP', 'symbol' => 'T$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($currencies as $currency) {
|
foreach ($currencies as $currency) {
|
||||||
|
@ -2402,6 +2402,9 @@ $LANG = array(
|
|||||||
'currency_libyan_dinar' => 'Libyan Dinar',
|
'currency_libyan_dinar' => 'Libyan Dinar',
|
||||||
'currency_silver_troy_ounce' => 'Silver Troy Ounce',
|
'currency_silver_troy_ounce' => 'Silver Troy Ounce',
|
||||||
'currency_gold_troy_ounce' => 'Gold Troy Ounce',
|
'currency_gold_troy_ounce' => 'Gold Troy Ounce',
|
||||||
|
'currency_nicaraguan_córdoba' => 'Nicaraguan Córdoba',
|
||||||
|
'currency_malagasy_ariary' => 'Malagasy ariary',
|
||||||
|
"currency_tongan_pa_anga" => "Tongan Pa'anga",
|
||||||
|
|
||||||
'review_app_help' => 'We hope you\'re enjoying using the app.<br/>If you\'d consider :link we\'d greatly appreciate it!',
|
'review_app_help' => 'We hope you\'re enjoying using the app.<br/>If you\'d consider :link we\'d greatly appreciate it!',
|
||||||
'writing_a_review' => 'writing a review',
|
'writing_a_review' => 'writing a review',
|
||||||
@ -3679,9 +3682,9 @@ $LANG = array(
|
|||||||
'send_date' => 'Send Date',
|
'send_date' => 'Send Date',
|
||||||
'auto_bill_on' => 'Auto Bill On',
|
'auto_bill_on' => 'Auto Bill On',
|
||||||
'minimum_under_payment_amount' => 'Minimum Under Payment Amount',
|
'minimum_under_payment_amount' => 'Minimum Under Payment Amount',
|
||||||
'allow_over_payment' => 'Allow Over Payment',
|
'allow_over_payment' => 'Allow Overpayment',
|
||||||
'allow_over_payment_help' => 'Support paying extra to accept tips',
|
'allow_over_payment_help' => 'Support paying extra to accept tips',
|
||||||
'allow_under_payment' => 'Allow Under Payment',
|
'allow_under_payment' => 'Allow Underpayment',
|
||||||
'allow_under_payment_help' => 'Support paying at minimum the partial/deposit amount',
|
'allow_under_payment_help' => 'Support paying at minimum the partial/deposit amount',
|
||||||
'test_mode' => 'Test Mode',
|
'test_mode' => 'Test Mode',
|
||||||
'calculated_rate' => 'Calculated Rate',
|
'calculated_rate' => 'Calculated Rate',
|
||||||
@ -3978,8 +3981,8 @@ $LANG = array(
|
|||||||
'account_balance' => 'Account Balance',
|
'account_balance' => 'Account Balance',
|
||||||
'thanks' => 'Thanks',
|
'thanks' => 'Thanks',
|
||||||
'minimum_required_payment' => 'Minimum required payment is :amount',
|
'minimum_required_payment' => 'Minimum required payment is :amount',
|
||||||
'under_payments_disabled' => 'Company doesn\'t support under payments.',
|
'under_payments_disabled' => 'Company doesn\'t support underpayments.',
|
||||||
'over_payments_disabled' => 'Company doesn\'t support over payments.',
|
'over_payments_disabled' => 'Company doesn\'t support overpayments.',
|
||||||
'saved_at' => 'Saved at :time',
|
'saved_at' => 'Saved at :time',
|
||||||
'credit_payment' => 'Credit applied to Invoice :invoice_number',
|
'credit_payment' => 'Credit applied to Invoice :invoice_number',
|
||||||
'credit_subject' => 'New credit :number from :account',
|
'credit_subject' => 'New credit :number from :account',
|
||||||
@ -4654,8 +4657,8 @@ $LANG = array(
|
|||||||
'search_purchase_order' => 'Search Purchase Order',
|
'search_purchase_order' => 'Search Purchase Order',
|
||||||
'search_purchase_orders' => 'Search Purchase Orders',
|
'search_purchase_orders' => 'Search Purchase Orders',
|
||||||
'login_url' => 'Login URL',
|
'login_url' => 'Login URL',
|
||||||
'enable_applying_payments' => 'Enable Applying Payments',
|
'enable_applying_payments' => 'Manual Overpayments',
|
||||||
'enable_applying_payments_help' => 'Support separately creating and applying payments',
|
'enable_applying_payments_help' => 'Support adding an overpayment amount manually on a payment',
|
||||||
'stock_quantity' => 'Stock Quantity',
|
'stock_quantity' => 'Stock Quantity',
|
||||||
'notification_threshold' => 'Notification Threshold',
|
'notification_threshold' => 'Notification Threshold',
|
||||||
'track_inventory' => 'Track Inventory',
|
'track_inventory' => 'Track Inventory',
|
||||||
@ -5180,6 +5183,8 @@ $LANG = array(
|
|||||||
'upcoming' => 'Upcoming',
|
'upcoming' => 'Upcoming',
|
||||||
'client_contact' => 'Client Contact',
|
'client_contact' => 'Client Contact',
|
||||||
'uncategorized' => 'Uncategorized',
|
'uncategorized' => 'Uncategorized',
|
||||||
|
'login_notification' => 'Login Notification',
|
||||||
|
'login_notification_help' => 'Sends an email notifying that a login has taken place.'
|
||||||
);
|
);
|
||||||
|
|
||||||
return $LANG;
|
return $LANG;
|
||||||
|
13076
openapi/api-docs.yaml
13076
openapi/api-docs.yaml
File diff suppressed because it is too large
Load Diff
@ -653,5 +653,91 @@
|
|||||||
$ref: '#/components/responses/429'
|
$ref: '#/components/responses/429'
|
||||||
5XX:
|
5XX:
|
||||||
description: 'Server error'
|
description: 'Server error'
|
||||||
|
default:
|
||||||
|
$ref: '#/components/responses/default'
|
||||||
|
/api/v1/reactivate_email/{bounce_id}:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- clients
|
||||||
|
summary: 'Removes email suppression of a user in the system'
|
||||||
|
description: 'Emails are suppressed by PostMark, when they receive a Hard bounce / Spam Complaint. This endpoint allows you to remove the suppression and send emails to the user again.'
|
||||||
|
operationId: reactivateEmail
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/X-API-TOKEN'
|
||||||
|
- $ref: '#/components/parameters/X-Requested-With'
|
||||||
|
- $ref: '#/components/parameters/include'
|
||||||
|
- name: bounce_id
|
||||||
|
in: path
|
||||||
|
description: 'The postmark Bounce ID reference'
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: string
|
||||||
|
example: 123243
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: 'Success'
|
||||||
|
headers:
|
||||||
|
X-MINIMUM-CLIENT-VERSION:
|
||||||
|
$ref: '#/components/headers/X-MINIMUM-CLIENT-VERSION'
|
||||||
|
X-RateLimit-Remaining:
|
||||||
|
$ref: '#/components/headers/X-RateLimit-Remaining'
|
||||||
|
X-RateLimit-Limit:
|
||||||
|
$ref: '#/components/headers/X-RateLimit-Limit'
|
||||||
|
400:
|
||||||
|
description: 'Postmark exception - generated if the suppression cannot be removed for any reason'
|
||||||
|
401:
|
||||||
|
$ref: '#/components/responses/401'
|
||||||
|
403:
|
||||||
|
$ref: '#/components/responses/403'
|
||||||
|
422:
|
||||||
|
$ref: '#/components/responses/422'
|
||||||
|
429:
|
||||||
|
$ref: '#/components/responses/429'
|
||||||
|
5XX:
|
||||||
|
description: 'Server error'
|
||||||
|
default:
|
||||||
|
$ref: '#/components/responses/default'
|
||||||
|
/api/v1/clients/{client}/updateTaxData:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- clients
|
||||||
|
summary: 'Update tax data'
|
||||||
|
description: 'Updates the clients tax data - if their address has changed'
|
||||||
|
operationId: updateClientTaxData
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/X-API-TOKEN'
|
||||||
|
- $ref: '#/components/parameters/X-Requested-With'
|
||||||
|
- $ref: '#/components/parameters/include'
|
||||||
|
- name: client
|
||||||
|
in: path
|
||||||
|
description: 'The Client Hashed ID reference'
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: string
|
||||||
|
example: V2J234DFA
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: 'Success'
|
||||||
|
headers:
|
||||||
|
X-MINIMUM-CLIENT-VERSION:
|
||||||
|
$ref: '#/components/headers/X-MINIMUM-CLIENT-VERSION'
|
||||||
|
X-RateLimit-Remaining:
|
||||||
|
$ref: '#/components/headers/X-RateLimit-Remaining'
|
||||||
|
X-RateLimit-Limit:
|
||||||
|
$ref: '#/components/headers/X-RateLimit-Limit'
|
||||||
|
400:
|
||||||
|
description: 'Postmark exception - generated if the suppression cannot be removed for any reason'
|
||||||
|
401:
|
||||||
|
$ref: '#/components/responses/401'
|
||||||
|
403:
|
||||||
|
$ref: '#/components/responses/403'
|
||||||
|
422:
|
||||||
|
$ref: '#/components/responses/422'
|
||||||
|
429:
|
||||||
|
$ref: '#/components/responses/429'
|
||||||
|
5XX:
|
||||||
|
description: 'Server error'
|
||||||
default:
|
default:
|
||||||
$ref: '#/components/responses/default'
|
$ref: '#/components/responses/default'
|
@ -1,4 +1,4 @@
|
|||||||
@if ($entity->documents->count() > 0 || $entity->company->documents->count() > 0 || ($entity->expense && $entity->expense->invoice_documents) || ($entity->task && $entity->company->invoice_task_documents))
|
@if ($entity->documents()->where('is_public',1)->count() > 0 || $entity->company->documents()->where('is_public',1)->count() > 0 || ($entity->expense && $entity->expense->invoice_documents) || ($entity->task && $entity->company->invoice_task_documents))
|
||||||
<div class="bg-white shadow sm:rounded-lg my-4">
|
<div class="bg-white shadow sm:rounded-lg my-4">
|
||||||
<div class="px-4 py-5 sm:p-6">
|
<div class="px-4 py-5 sm:p-6">
|
||||||
<div class="sm:flex sm:items-start sm:justify-between">
|
<div class="sm:flex sm:items-start sm:justify-between">
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
{{ ctrans('texts.public_notes') }}
|
{{ ctrans('texts.public_notes') }}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
{{ $invoice->public_notes }}
|
{!! html_entity_decode($invoice->public_notes) !!}
|
||||||
</dd>
|
</dd>
|
||||||
@else
|
@else
|
||||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||||
|
@ -164,6 +164,8 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale']
|
|||||||
Route::post('clients/{client}/{mergeable_client}/merge', [ClientController::class, 'merge'])->name('clients.merge')->middleware('password_protected');
|
Route::post('clients/{client}/{mergeable_client}/merge', [ClientController::class, 'merge'])->name('clients.merge')->middleware('password_protected');
|
||||||
Route::post('clients/bulk', [ClientController::class, 'bulk'])->name('clients.bulk');
|
Route::post('clients/bulk', [ClientController::class, 'bulk'])->name('clients.bulk');
|
||||||
|
|
||||||
|
Route::post('reactivate_email/{bounce_id}', [ClientController::class, 'reactivateEmail'])->name('clients.reactivate_email');
|
||||||
|
|
||||||
Route::post('filters/{entity}', [FilterController::class, 'index'])->name('filters');
|
Route::post('filters/{entity}', [FilterController::class, 'index'])->name('filters');
|
||||||
|
|
||||||
Route::resource('client_gateway_tokens', ClientGatewayTokenController::class);
|
Route::resource('client_gateway_tokens', ClientGatewayTokenController::class);
|
||||||
|
@ -65,6 +65,34 @@ class ClientTest extends TestCase
|
|||||||
$this->makeTestData();
|
$this->makeTestData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testStoreClientFixes()
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
"contacts" => [
|
||||||
|
[
|
||||||
|
"email" => "tenda@gmail.com",
|
||||||
|
"first_name" => "Tenda",
|
||||||
|
"is_primary" => True,
|
||||||
|
"last_name" => "Bavuma",
|
||||||
|
"password" => null,
|
||||||
|
"send_email" => True
|
||||||
|
],
|
||||||
|
],
|
||||||
|
"country_id" => "356",
|
||||||
|
"display_name" => "Tenda Bavuma",
|
||||||
|
"name" => "Tenda Bavuma",
|
||||||
|
"shipping_country_id" => "356",
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->postJson('/api/v1/clients', $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
}
|
||||||
|
|
||||||
public function testClientMergeContactDrop()
|
public function testClientMergeContactDrop()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@ use App\Models\Account;
|
|||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Expense;
|
use App\Models\Expense;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use Tests\MockAccountData;
|
|
||||||
use App\Models\CompanyToken;
|
use App\Models\CompanyToken;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
use App\Export\CSV\TaskExport;
|
use App\Export\CSV\TaskExport;
|
||||||
@ -30,8 +29,6 @@ use App\Export\CSV\ProductExport;
|
|||||||
use App\DataMapper\CompanySettings;
|
use App\DataMapper\CompanySettings;
|
||||||
use App\Export\CSV\PaymentExport;
|
use App\Export\CSV\PaymentExport;
|
||||||
use App\Factory\CompanyUserFactory;
|
use App\Factory\CompanyUserFactory;
|
||||||
use App\Factory\InvoiceItemFactory;
|
|
||||||
use App\Services\Report\ARDetailReport;
|
|
||||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -262,6 +259,21 @@ class ReportCsvGenerationTest extends TestCase
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testForcedInsertionOfMandatoryColumns()
|
||||||
|
{
|
||||||
|
$forced = ['client.name'];
|
||||||
|
|
||||||
|
$report_keys = ['invoice.number','client.name', 'invoice.amount'];
|
||||||
|
$array = array_merge($report_keys, array_diff($forced, $report_keys));
|
||||||
|
|
||||||
|
$this->assertEquals('client.name', $array[1]);
|
||||||
|
|
||||||
|
$report_keys = ['invoice.number','invoice.amount'];
|
||||||
|
$array = array_merge($report_keys, array_diff($forced, $report_keys));
|
||||||
|
|
||||||
|
$this->assertEquals('client.name', $array[2]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public function testVendorCsvGeneration()
|
public function testVendorCsvGeneration()
|
||||||
{
|
{
|
||||||
@ -322,7 +334,7 @@ class ReportCsvGenerationTest extends TestCase
|
|||||||
$data = $export->returnJson();
|
$data = $export->returnJson();
|
||||||
|
|
||||||
$this->assertNotNull($data);
|
$this->assertNotNull($data);
|
||||||
// nlog($data);
|
// nlog($data);
|
||||||
// $this->assertEquals(0, $this->traverseJson($data, 'columns.0.identifier'));
|
// $this->assertEquals(0, $this->traverseJson($data, 'columns.0.identifier'));
|
||||||
$this->assertEquals('Vendor Name', $this->traverseJson($data, 'columns.9.display_value'));
|
$this->assertEquals('Vendor Name', $this->traverseJson($data, 'columns.9.display_value'));
|
||||||
$this->assertEquals('vendor', $this->traverseJson($data, '0.0.entity'));
|
$this->assertEquals('vendor', $this->traverseJson($data, '0.0.entity'));
|
||||||
@ -1021,6 +1033,44 @@ class ReportCsvGenerationTest extends TestCase
|
|||||||
'X-API-TOKEN' => $this->token,
|
'X-API-TOKEN' => $this->token,
|
||||||
])->post('/api/v1/reports/recurring_invoices', $data)->assertStatus(200);
|
])->post('/api/v1/reports/recurring_invoices', $data)->assertStatus(200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testRecurringInvoiceColumnsCsvGeneration()
|
||||||
|
{
|
||||||
|
|
||||||
|
\App\Models\RecurringInvoice::factory()->create([
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
'client_id' => $this->client->id,
|
||||||
|
'amount' => 100,
|
||||||
|
'balance' => 50,
|
||||||
|
'number' => '1234',
|
||||||
|
'status_id' => 2,
|
||||||
|
'discount' => 10,
|
||||||
|
'po_number' => '1234',
|
||||||
|
'public_notes' => 'Public',
|
||||||
|
'private_notes' => 'Private',
|
||||||
|
'terms' => 'Terms',
|
||||||
|
'frequency_id' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'date_range' => 'all',
|
||||||
|
'report_keys' => [],
|
||||||
|
'send_email' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->post('/api/v1/reports/recurring_invoices', $data);
|
||||||
|
|
||||||
|
$csv = $response->streamedContent();
|
||||||
|
|
||||||
|
$this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Recurring Invoice Invoice Number'));
|
||||||
|
$this->assertEquals('Daily', $this->getFirstValueByColumn($csv, 'Recurring Invoice How Often'));
|
||||||
|
$this->assertEquals('Active', $this->getFirstValueByColumn($csv, 'Recurring Invoice Status'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1121,7 +1171,7 @@ class ReportCsvGenerationTest extends TestCase
|
|||||||
public function testQuoteItemsCustomColumnsCsvGeneration()
|
public function testQuoteItemsCustomColumnsCsvGeneration()
|
||||||
{
|
{
|
||||||
|
|
||||||
\App\Models\Quote::factory()->create([
|
$q = \App\Models\Quote::factory()->create([
|
||||||
'user_id' => $this->user->id,
|
'user_id' => $this->user->id,
|
||||||
'company_id' => $this->company->id,
|
'company_id' => $this->company->id,
|
||||||
'client_id' => $this->client->id,
|
'client_id' => $this->client->id,
|
||||||
@ -1167,7 +1217,6 @@ class ReportCsvGenerationTest extends TestCase
|
|||||||
|
|
||||||
$csv = $response->streamedContent();
|
$csv = $response->streamedContent();
|
||||||
|
|
||||||
|
|
||||||
$this->assertEquals('bob', $this->getFirstValueByColumn($csv, 'Client Name'));
|
$this->assertEquals('bob', $this->getFirstValueByColumn($csv, 'Client Name'));
|
||||||
$this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Quote Number'));
|
$this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Quote Number'));
|
||||||
$this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Item Quantity'));
|
$this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Item Quantity'));
|
||||||
|
@ -11,20 +11,21 @@
|
|||||||
|
|
||||||
namespace Tests\Feature;
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Tests\MockAccountData;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
use Tests\MockAccountData;
|
use App\DataMapper\Settings\SettingsData;
|
||||||
use Tests\TestCase;
|
use Spatie\LaravelData\Support\Wrapping\WrapExecutionType;
|
||||||
|
|
||||||
class GroupSettingTest extends TestCase
|
class GroupSettingTest extends TestCase
|
||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
|
|
||||||
//use DatabaseTransactions;
|
|
||||||
use MockAccountData;
|
use MockAccountData;
|
||||||
|
|
||||||
|
public $faker;
|
||||||
|
|
||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
@ -38,6 +39,85 @@ class GroupSettingTest extends TestCase
|
|||||||
$this->makeTestData();
|
$this->makeTestData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCastingMagic()
|
||||||
|
{
|
||||||
|
|
||||||
|
$settings = new \stdClass;
|
||||||
|
$settings->currency_id = '1';
|
||||||
|
$settings->tax_name1 = '';
|
||||||
|
$settings->tax_rate1 = 0;
|
||||||
|
$s = new SettingsData();
|
||||||
|
$settings = $s->cast($settings)->toObject();
|
||||||
|
|
||||||
|
$this->assertEquals("", $settings->tax_name1);
|
||||||
|
$settings = null;
|
||||||
|
|
||||||
|
$settings = new \stdClass;
|
||||||
|
$settings->currency_id = '1';
|
||||||
|
$settings->tax_name1 = "1";
|
||||||
|
$settings->tax_rate1 = 0;
|
||||||
|
|
||||||
|
$settings = $s->cast($settings)->toObject();
|
||||||
|
|
||||||
|
$this->assertEquals("1", $settings->tax_name1);
|
||||||
|
|
||||||
|
$settings = $s->cast($settings)->toArray();
|
||||||
|
$this->assertEquals("1", $settings['tax_name1']);
|
||||||
|
|
||||||
|
$settings = new \stdClass;
|
||||||
|
$settings->currency_id = '1';
|
||||||
|
$settings->tax_name1 = [];
|
||||||
|
$settings->tax_rate1 = 0;
|
||||||
|
|
||||||
|
$settings = $s->cast($settings)->toObject();
|
||||||
|
|
||||||
|
$this->assertEquals("", $settings->tax_name1);
|
||||||
|
|
||||||
|
$settings = $s->cast($settings)->toArray();
|
||||||
|
$this->assertEquals("", $settings['tax_name1']);
|
||||||
|
|
||||||
|
$settings = new \stdClass;
|
||||||
|
$settings->currency_id = '1';
|
||||||
|
$settings->tax_name1 = new \stdClass;
|
||||||
|
$settings->tax_rate1 = 0;
|
||||||
|
|
||||||
|
$settings = $s->cast($settings)->toObject();
|
||||||
|
|
||||||
|
$this->assertEquals("", $settings->tax_name1);
|
||||||
|
|
||||||
|
$settings = $s->cast($settings)->toArray();
|
||||||
|
$this->assertEquals("", $settings['tax_name1']);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// nlog(json_encode($settings));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTaxNameInGroupFilters()
|
||||||
|
{
|
||||||
|
$settings = new \stdClass;
|
||||||
|
$settings->currency_id = '1';
|
||||||
|
$settings->tax_name1 = '';
|
||||||
|
$settings->tax_rate1 = 0;
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'name' => 'testX',
|
||||||
|
'settings' => $settings,
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->postJson('/api/v1/group_settings', $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
$arr = $response->json();
|
||||||
|
|
||||||
|
$this->assertEquals("", (string)NULL);
|
||||||
|
$this->assertNotNull($arr['data']['settings']['tax_name1']);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testAddGroupFilters()
|
public function testAddGroupFilters()
|
||||||
{
|
{
|
||||||
|
@ -32,6 +32,8 @@ class InvoiceEmailTest extends TestCase
|
|||||||
use DatabaseTransactions;
|
use DatabaseTransactions;
|
||||||
use GeneratesCounter;
|
use GeneratesCounter;
|
||||||
|
|
||||||
|
public $faker;
|
||||||
|
|
||||||
protected function setUp() :void
|
protected function setUp() :void
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
@ -48,6 +50,14 @@ class InvoiceEmailTest extends TestCase
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testInvalidEmailParsing()
|
||||||
|
{
|
||||||
|
$email = 'illegal@example.com';
|
||||||
|
|
||||||
|
$this->assertTrue(strpos($email, '@example.com') !== false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testClientEmailHistory()
|
public function testClientEmailHistory()
|
||||||
{
|
{
|
||||||
$system_log = new SystemLog();
|
$system_log = new SystemLog();
|
||||||
|
@ -13,7 +13,9 @@ namespace Tests\Feature;
|
|||||||
|
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
use App\Models\Design;
|
use App\Models\Design;
|
||||||
|
use App\Utils\HtmlEngine;
|
||||||
use Tests\MockAccountData;
|
use Tests\MockAccountData;
|
||||||
|
use App\Models\InvoiceInvitation;
|
||||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
|
||||||
@ -41,6 +43,30 @@ class LiveDesignTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSyntheticInvitations()
|
||||||
|
{
|
||||||
|
$this->assertGreaterThanOrEqual(1, $this->client->contacts->count());
|
||||||
|
|
||||||
|
$ii = InvoiceInvitation::factory()
|
||||||
|
->for($this->invoice)
|
||||||
|
->for($this->client->contacts->first(), 'contact')
|
||||||
|
->for($this->company)
|
||||||
|
->for($this->user)
|
||||||
|
->make();
|
||||||
|
|
||||||
|
$this->assertInstanceOf(InvoiceInvitation::class, $ii);
|
||||||
|
|
||||||
|
$engine = new HtmlEngine($ii);
|
||||||
|
|
||||||
|
$this->assertNotNull($engine);
|
||||||
|
|
||||||
|
$data = $engine->generateLabelsAndValues();
|
||||||
|
|
||||||
|
$this->assertIsArray($data);
|
||||||
|
|
||||||
|
nlog($data);
|
||||||
|
}
|
||||||
|
|
||||||
public function testDesignRoute200()
|
public function testDesignRoute200()
|
||||||
{
|
{
|
||||||
$data = [
|
$data = [
|
||||||
|
@ -28,6 +28,10 @@ class GroupSettingsTest extends TestCase
|
|||||||
use DatabaseTransactions;
|
use DatabaseTransactions;
|
||||||
use ClientGroupSettingsSaver;
|
use ClientGroupSettingsSaver;
|
||||||
|
|
||||||
|
public $company_settings;
|
||||||
|
public $client_settings;
|
||||||
|
public $settings;
|
||||||
|
|
||||||
protected function setUp() :void
|
protected function setUp() :void
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
Loading…
Reference in New Issue
Block a user