1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 21:22:58 +01:00

Merge pull request #4292 from turbo124/v5-stable

Fixes for Stripe, PDF Creation, Docker compatiblity
This commit is contained in:
David Bomba 2020-11-11 11:16:11 +11:00 committed by GitHub
commit 3fde3f4035
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
208 changed files with 16821 additions and 13721 deletions

View File

@ -3,7 +3,6 @@ APP_DEBUG=true
APP_LOCALE=en
APP_URL=http://127.0.0.1:8000
APP_KEY=s7epnjtomsdond5zgfqgaqmwhhcjct02
APP_CIPHER=AES-256-CBC
REQUIRE_HTTPS=false
NINJA_ENVIRONMENT=development
@ -26,4 +25,3 @@ MAIL_FROM_ADDRESS=
MAIL_PASSWORD=
MAILGUN_DOMAIN=
MAILGUN_SECRET=
AUTH_PROVIDER=users

View File

@ -1 +1 @@
5.0.23
5.0.24

View File

@ -355,8 +355,6 @@ class CheckData extends Command
$wrong_balances = 0;
$wrong_paid_to_dates = 0;
//todo reversing an invoice breaks the check data at this point;
Client::cursor()->each(function ($client) use ($wrong_balances) {
$client->invoices->where('is_deleted', false)->each(function ($invoice) use ($wrong_balances, $client) {
$total_amount = $invoice->payments->sum('pivot.amount');

View File

@ -340,10 +340,6 @@ class CreateSingleAccount extends Command
$this->invoice_repo->markSent($invoice);
// if (rand(0, 1)) {
// $invoice = $invoice->service()->markPaid()->save();
// }
//@todo this slow things down, but gives us PDFs of the invoices for inspection whilst debugging.
event(new InvoiceWasCreated($invoice, $invoice->company, Ninja::eventVars()));
}
@ -516,8 +512,8 @@ class CreateSingleAccount extends Command
$cg->user_id = $user->id;
$cg->gateway_key = 'd14dd26a37cecc30fdd65700bfb55b23';
$cg->require_cvv = true;
$cg->show_billing_address = true;
$cg->show_shipping_address = true;
$cg->require_billing_address = true;
$cg->require_shipping_address = true;
$cg->update_details = true;
$cg->config = encrypt(config('ninja.testvars.stripe'));
$cg->save();
@ -527,8 +523,8 @@ class CreateSingleAccount extends Command
// $cg->user_id = $user->id;
// $cg->gateway_key = 'd14dd26a37cecc30fdd65700bfb55b23';
// $cg->require_cvv = true;
// $cg->show_billing_address = true;
// $cg->show_shipping_address = true;
// $cg->require_billing_address = true;
// $cg->require_shipping_address = true;
// $cg->update_details = true;
// $cg->config = encrypt(config('ninja.testvars.stripe'));
// $cg->save();
@ -540,8 +536,8 @@ class CreateSingleAccount extends Command
$cg->user_id = $user->id;
$cg->gateway_key = '38f2c48af60c7dd69e04248cbb24c36e';
$cg->require_cvv = true;
$cg->show_billing_address = true;
$cg->show_shipping_address = true;
$cg->require_billing_address = true;
$cg->require_shipping_address = true;
$cg->update_details = true;
$cg->config = encrypt(config('ninja.testvars.paypal'));
$cg->save();
@ -553,8 +549,8 @@ class CreateSingleAccount extends Command
$cg->user_id = $user->id;
$cg->gateway_key = '3758e7f7c6f4cecf0f4f348b9a00f456';
$cg->require_cvv = true;
$cg->show_billing_address = true;
$cg->show_shipping_address = true;
$cg->require_billing_address = true;
$cg->require_shipping_address = true;
$cg->update_details = true;
$cg->config = encrypt(config('ninja.testvars.checkout'));
$cg->save();
@ -566,8 +562,8 @@ class CreateSingleAccount extends Command
$cg->user_id = $user->id;
$cg->gateway_key = '3b6621f970ab18887c4f6dca78d3f8bb';
$cg->require_cvv = true;
$cg->show_billing_address = true;
$cg->show_shipping_address = true;
$cg->require_billing_address = true;
$cg->require_shipping_address = true;
$cg->update_details = true;
$cg->config = encrypt(config('ninja.testvars.authorize'));
$cg->save();

View File

@ -516,7 +516,7 @@ class CreateTestData extends Command
if (rand(0, 1)) {
$invoice = $invoice->service()->markPaid()->save();
}
//@todo this slow things down, but gives us PDFs of the invoices for inspection whilst debugging.
event(new InvoiceWasCreated($invoice, $invoice->company, Ninja::eventVars()));
}

View File

@ -364,10 +364,14 @@ class DemoMode extends Command
private function createProject($client, $assigned_user_id = null)
{
$vendor = Project::factory()->create([
$project = Project::factory()->create([
'user_id' => $client->user->id,
'company_id' => $client->company_id,
'client_id' => $client->id,
]);
$project->number = $this->getNextProjectNumber($project);
$project->save();
}
private function createInvoice($client, $assigned_user_id = null)
@ -431,7 +435,7 @@ class DemoMode extends Command
$payment->save();
});
}
//@todo this slow things down, but gives us PDFs of the invoices for inspection whilst debugging.
event(new InvoiceWasCreated($invoice, $invoice->company, Ninja::eventVars()));
}

View File

@ -0,0 +1,85 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Console\Commands;
use App\Jobs\Ninja\SendReminders;
use App\Jobs\Util\WebHookHandler;
use App\Models\Invoice;
use App\Models\Quote;
use App\Models\Webhook;
use Illuminate\Console\Command;
class SendRemindersCron extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'ninja:send-reminders';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Force send all reminders';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
SendReminders::dispatchNow();
$this->webHookOverdueInvoices();
$this->webHookExpiredQuotes();
}
private function webHookOverdueInvoices()
{
$invoices = Invoice::where('is_deleted', 0)
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
->where('balance', '>', 0)
->whereDate('due_date', now()->subDays(1)->startOfDay())
->cursor();
$invoices->each(function ($invoice){
WebHookHandler::dispatch(Webhook::EVENT_LATE_INVOICE, $invoice);
});
}
private function webHookExpiredQuotes()
{
$quotes = Quote::where('is_deleted', 0)
->where('status_id', Quote::STATUS_SENT)
->whereDate('due_date', now()->subDays(1)->startOfDay())
->cursor();
$quotes->each(function ($quote){
WebHookHandler::dispatch(Webhook::EVENT_EXPIRED_QUOTE, $quote);
});
}
}

View File

@ -17,7 +17,6 @@ use App\Factory\ClientFactory;
use App\Factory\CompanyUserFactory;
use App\Factory\InvoiceFactory;
use App\Factory\InvoiceInvitationFactory;
use App\Helpers\Email\InvoiceEmail;
use App\Jobs\Invoice\CreateEntityPdf;
use App\Mail\TemplateEmail;
use App\Models\Account;
@ -155,16 +154,15 @@ class SendTestEmails extends Command
$cc_emails = [config('ninja.testvars.test_email')];
$bcc_emails = [config('ninja.testvars.test_email')];
$email_builder = (new InvoiceEmail())->build($ii, 'invoice');
$email_builder->setFooter($message['footer'])
->setSubject($message['subject'])
->setBody($message['body']);
Mail::to(config('ninja.testvars.test_email'), 'Mr Test')
->cc($cc_emails)
->bcc($bcc_emails)
// Mail::to(config('ninja.testvars.test_email'), 'Mr Test')
// ->cc($cc_emails)
// ->bcc($bcc_emails)
//->replyTo(also_available_if_needed)
->send(new TemplateEmail($email_builder, $user, $client));
//->send(new TemplateEmail($email_builder, $user, $client));
}
}

View File

@ -11,7 +11,6 @@
namespace App\DataMapper;
use App\DataMapper\CompanySettings;
use App\Utils\Traits\MakesHash;
use stdClass;
@ -24,177 +23,176 @@ class CompanySettings extends BaseSettings
/*Group settings based on functionality*/
/*Invoice*/
public $auto_archive_invoice = false;
public $auto_archive_invoice = false; // @implemented
public $lock_invoices = 'off'; //off,when_sent,when_paid
public $lock_invoices = 'off'; //off,when_sent,when_paid //@implemented
public $enable_client_portal_tasks = false;
public $enable_client_portal_password = false;
public $enable_client_portal = true; //implemented
public $enable_client_portal_dashboard = true; //implemented
public $signature_on_pdf = false;
public $document_email_attachment = false;
//public $send_portal_password = false;
public $enable_client_portal_tasks = false; //@ben to implement
public $enable_client_portal_password = false; //@implemented
public $enable_client_portal = true; //@implemented
public $enable_client_portal_dashboard = true; // @TODO There currently is no dashboard so this is pending
public $signature_on_pdf = false; //@implemented
public $document_email_attachment = false; //@TODO I assume this is 3rd party attachments on the entity to be included
public $portal_design_id = '1';
public $portal_design_id = '1'; //?@deprecated
public $timezone_id = '';
public $date_format_id = '';
public $military_time = false;
public $timezone_id = ''; //@implemented
public $date_format_id = ''; //@implemented
public $military_time = false; // @TODOImplemented in Tasks only?
public $language_id = '';
public $show_currency_code = false;
public $language_id = ''; //@implemented
public $show_currency_code = false; //@implemented
public $company_gateway_ids = '';
public $company_gateway_ids = ''; //@implemented
public $currency_id = '1';
public $currency_id = '1'; //@implemented
public $custom_value1 = '';
public $custom_value2 = '';
public $custom_value3 = '';
public $custom_value4 = '';
public $custom_value1 = ''; //@implemented
public $custom_value2 = ''; //@implemented
public $custom_value3 = ''; //@implemented
public $custom_value4 = ''; //@implemented
public $default_task_rate = 0;
public $default_task_rate = 0; // @TODO Where do we inject this?
public $payment_terms = '';
public $send_reminders = false;
public $payment_terms = ''; //@implemented
public $send_reminders = false; //@TODO
public $custom_message_dashboard = '';
public $custom_message_unpaid_invoice = '';
public $custom_message_paid_invoice = '';
public $custom_message_unapproved_quote = '';
public $auto_archive_quote = false;
public $auto_convert_quote = true;
public $auto_email_invoice = true;
public $custom_message_dashboard = ''; // @TODO There currently is no dashboard so this is pending
public $custom_message_unpaid_invoice = ''; //@ben to implement
public $custom_message_paid_invoice = ''; //@ben to implement
public $custom_message_unapproved_quote = ''; //@ben to implement
public $auto_archive_quote = false; //@implemented
public $auto_convert_quote = true; //@implemented
public $auto_email_invoice = true; //@only used for Recurring Invoices, if set to false, we never send?
public $inclusive_taxes = false;
public $quote_footer = '';
public $inclusive_taxes = false; //@implemented
public $quote_footer = ''; //@implmented
public $translations;
public $translations; //@TODO not used anywhere
public $counter_number_applied = 'when_saved'; // when_saved , when_sent
public $quote_number_applied = 'when_saved'; // when_saved , when_sent
public $counter_number_applied = 'when_saved'; // when_saved , when_sent //@implemented
public $quote_number_applied = 'when_saved'; // when_saved , when_sent //@implemented
/* Counters */
public $invoice_number_pattern = '';
public $invoice_number_counter = 1;
public $invoice_number_pattern = ''; //@implemented
public $invoice_number_counter = 1; //@implemented
public $recurring_invoice_number_pattern = '';
public $recurring_invoice_number_counter = 1;
public $recurring_invoice_number_pattern = ''; //@implemented
public $recurring_invoice_number_counter = 1; //@implemented
public $quote_number_pattern = '';
public $quote_number_counter = 1;
public $quote_number_pattern = ''; //@implemented
public $quote_number_counter = 1; //@implemented
public $client_number_pattern = '';
public $client_number_counter = 1;
public $client_number_pattern = ''; //@implemented
public $client_number_counter = 1; //@implemented
public $credit_number_pattern = '';
public $credit_number_counter = 1;
public $credit_number_pattern = ''; //@implemented
public $credit_number_counter = 1; //@implemented
public $task_number_pattern = '';
public $task_number_counter = 1;
public $task_number_pattern = ''; //@implemented
public $task_number_counter = 1; //@implemented
public $expense_number_pattern = '';
public $expense_number_counter = 1;
public $expense_number_pattern = ''; //@implemented
public $expense_number_counter = 1; //@implemented
public $vendor_number_pattern = '';
public $vendor_number_counter = 1;
public $vendor_number_pattern = ''; //@implemented
public $vendor_number_counter = 1; //@implemented
public $ticket_number_pattern = '';
public $ticket_number_counter = 1;
public $ticket_number_pattern = ''; //@implemented
public $ticket_number_counter = 1; //@implemented
public $payment_number_pattern = '';
public $payment_number_counter = 1;
public $payment_number_pattern = ''; //@implemented
public $payment_number_counter = 1; //@implemented
public $project_number_pattern = '';
public $project_number_counter = 1;
public $project_number_pattern = ''; //@implemented
public $project_number_counter = 1; //@implemented
public $shared_invoice_quote_counter = false;
public $recurring_number_prefix = 'R';
public $reset_counter_frequency_id = '0';
public $reset_counter_date = '';
public $counter_padding = 4;
public $shared_invoice_quote_counter = false; //@implemented
public $recurring_number_prefix = 'R'; //@implemented
public $reset_counter_frequency_id = '0'; //@implemented
public $reset_counter_date = ''; //@implemented
public $counter_padding = 4; //@implemented
public $auto_bill = 'off'; //off,always,optin,optout
public $auto_bill_date = 'on_due_date'; // on_due_date , on_send_date
public $auto_bill = 'off'; //off,always,optin,optout //@implemented
public $auto_bill_date = 'on_due_date'; // on_due_date , on_send_date //@implemented
public $design = 'views/pdf/design1.blade.php';
//public $design = 'views/pdf/design1.blade.php'; //@deprecated - never used
public $invoice_terms = '';
public $quote_terms = '';
public $invoice_taxes = 0;
public $invoice_terms = ''; //@implemented
public $quote_terms = ''; //@implemented
public $invoice_taxes = 0; // ? used in AP only?
// public $enabled_item_tax_rates = 0;
public $invoice_design_id = 'VolejRejNm';
public $quote_design_id = 'VolejRejNm';
public $credit_design_id = 'VolejRejNm';
public $invoice_footer = '';
public $credit_footer = '';
public $credit_terms = '';
public $invoice_labels = '';
public $tax_name1 = '';
public $tax_rate1 = 0;
public $tax_name2 = '';
public $tax_rate2 = 0;
public $tax_name3 = '';
public $tax_rate3 = 0;
public $payment_type_id = '0';
public $invoice_fields = '';
public $invoice_design_id = 'VolejRejNm'; //@implemented
public $quote_design_id = 'VolejRejNm'; //@implemented
public $credit_design_id = 'VolejRejNm'; //@implemented
public $invoice_footer = ''; //@implemented
public $credit_footer = ''; //@implemented
public $credit_terms = ''; //@implemented
public $invoice_labels = ''; //@TODO used in AP only?
public $tax_name1 = ''; //@TODO where do we use this?
public $tax_rate1 = 0; //@TODO where do we use this?
public $tax_name2 = ''; //@TODO where do we use this?
public $tax_rate2 = 0; //@TODO where do we use this?
public $tax_name3 = ''; //@TODO where do we use this?
public $tax_rate3 = 0; //@TODO where do we use this?
public $payment_type_id = '0'; //@TODO where do we use this?
public $invoice_fields = ''; //@TODO is this redundant, we store this in the custom_fields on the company?
public $show_accept_invoice_terms = false;
public $show_accept_quote_terms = false;
public $require_invoice_signature = false;
public $require_quote_signature = false;
public $show_accept_invoice_terms = false; //@TODO ben to confirm
public $show_accept_quote_terms = false; //@TODO ben to confirm
public $require_invoice_signature = false; //@TODO ben to confirm
public $require_quote_signature = false; //@TODO ben to confirm
//email settings
public $email_sending_method = 'default'; //enum 'default','gmail'
public $gmail_sending_user_id = '0';
public $email_sending_method = 'default'; //enum 'default','gmail' //@implemented
public $gmail_sending_user_id = '0'; //@implemented
public $reply_to_email = '';
public $bcc_email = '';
public $pdf_email_attachment = false;
public $ubl_email_attachment = false;
public $reply_to_email = ''; //@TODO
public $bcc_email = ''; //@TODO
public $pdf_email_attachment = false; //@implemented
public $ubl_email_attachment = false; //@implemented
public $email_style = 'light'; //plain, light, dark, custom
public $email_style_custom = ''; //the template itself
public $email_subject_invoice = '';
public $email_subject_quote = '';
public $email_subject_credit = '';
public $email_subject_payment = '';
public $email_subject_payment_partial = '';
public $email_subject_statement = '';
public $email_template_invoice = '';
public $email_template_credit = '';
public $email_template_quote = '';
public $email_template_payment = '';
public $email_template_payment_partial = '';
public $email_template_statement = '';
public $email_subject_reminder1 = '';
public $email_subject_reminder2 = '';
public $email_subject_reminder3 = '';
public $email_subject_reminder_endless = '';
public $email_template_reminder1 = '';
public $email_template_reminder2 = '';
public $email_template_reminder3 = '';
public $email_template_reminder_endless = '';
public $email_signature = '';
public $enable_email_markup = true;
public $email_style = 'light'; //plain, light, dark, custom //@implemented
public $email_style_custom = ''; //the template itself //@implemented
public $email_subject_invoice = ''; //@implemented
public $email_subject_quote = ''; //@implemented
public $email_subject_credit = ''; //@implemented
public $email_subject_payment = ''; //@implemented
public $email_subject_payment_partial = ''; //@implemented
public $email_subject_statement = ''; //@implemented
public $email_template_invoice = ''; //@implemented
public $email_template_credit = ''; //@implemented
public $email_template_quote = ''; //@implemented
public $email_template_payment = ''; //@implemented
public $email_template_payment_partial = ''; //@implemented
public $email_template_statement = ''; //@implemented
public $email_subject_reminder1 = ''; //@implemented
public $email_subject_reminder2 = ''; //@implemented
public $email_subject_reminder3 = ''; //@implemented
public $email_subject_reminder_endless = ''; //@implemented
public $email_template_reminder1 = ''; //@implemented
public $email_template_reminder2 = ''; //@implemented
public $email_template_reminder3 = ''; //@implemented
public $email_template_reminder_endless = ''; //@implemented
public $email_signature = ''; //@implemented
public $enable_email_markup = true; //@TODO
public $email_subject_custom1 = '';
public $email_subject_custom2 = '';
public $email_subject_custom3 = '';
public $email_subject_custom1 = ''; //@TODO
public $email_subject_custom2 = ''; //@TODO
public $email_subject_custom3 = ''; //@TODO
public $email_template_custom1 = '';
public $email_template_custom2 = '';
public $email_template_custom3 = '';
public $email_template_custom1 = ''; //@TODO
public $email_template_custom2 = ''; //@TODO
public $email_template_custom3 = ''; //@TODO
public $enable_reminder1 = false;
public $enable_reminder2 = false;
public $enable_reminder3 = false;
public $enable_reminder_endless = false;
public $enable_reminder1 = false; //@partially implmemented
public $enable_reminder2 = false; //@partially implmemented
public $enable_reminder3 = false; //@partially implmemented
public $enable_reminder_endless = false; //@partially implmemented
public $num_days_reminder1 = 0;
public $num_days_reminder2 = 0;
public $num_days_reminder3 = 0;
public $num_days_reminder1 = 0;//@partially implmemented
public $num_days_reminder2 = 0;//@partially implmemented
public $num_days_reminder3 = 0;//@partially implmemented
public $schedule_reminder1 = ''; // (enum: after_invoice_date, before_due_date, after_due_date)
public $schedule_reminder2 = ''; // (enum: after_invoice_date, before_due_date, after_due_date)
@ -202,32 +200,36 @@ class CompanySettings extends BaseSettings
public $reminder_send_time = 32400; //number of seconds from UTC +0 to send reminders
public $late_fee_amount1 = 0;
public $late_fee_amount2 = 0;
public $late_fee_amount3 = 0;
public $late_fee_amount1 = 0; //@TODO
public $late_fee_amount2 = 0; //@TODO
public $late_fee_amount3 = 0; //@TODO
public $endless_reminder_frequency_id = '0';
public $late_fee_endless_amount = 0;
public $late_fee_endless_percent = 0;
public $late_fee_percent1 = 0; //@TODO
public $late_fee_percent2 = 0; //@TODO
public $late_fee_percent3 = 0; //@TODO
public $endless_reminder_frequency_id = '0'; //@implemented
public $late_fee_endless_amount = 0; //@TODO
public $late_fee_endless_percent = 0; //@TODO
public $client_online_payment_notification = true; //@todo implement in notifications
public $client_manual_payment_notification = true; //@todo implement in notifications
/* Company Meta data that we can use to build sub companies*/
public $name = '';
public $company_logo = '';
public $website = '';
public $address1 = '';
public $address2 = '';
public $city = '';
public $state = '';
public $postal_code = '';
public $phone = '';
public $email = '';
public $country_id;
public $vat_number = '';
public $id_number = '';
public $name = ''; //@implemented
public $company_logo = ''; //@implemented
public $website = ''; //@implemented
public $address1 = ''; //@implemented
public $address2 = ''; //@implemented
public $city = ''; //@implemented
public $state = ''; //@implemented
public $postal_code = ''; //@implemented
public $phone = ''; //@implemented
public $email = ''; //@implemented
public $country_id; //@implemented
public $vat_number = ''; //@implemented
public $id_number = ''; //@implemented
public $page_size = 'A4'; //Letter, Legal, Tabloid, Ledger, A0, A1, A2, A3, A4, A5, A6
public $font_size = 9;
@ -236,26 +238,26 @@ class CompanySettings extends BaseSettings
public $primary_color = '#4caf50';
public $secondary_color = '#2196f3';
public $hide_paid_to_date = false;
public $embed_documents = false;
public $all_pages_header = false;
public $all_pages_footer = false;
public $pdf_variables = '';
public $hide_paid_to_date = false; //@TODO where?
public $embed_documents = false; //@TODO
public $all_pages_header = false; //@implemented
public $all_pages_footer = false; //@implemented
public $pdf_variables = ''; //@implemented
public $portal_custom_head = '';
public $portal_custom_css = '';
public $portal_custom_footer = '';
public $portal_custom_js = '';
public $portal_custom_head = ''; //@TODO
public $portal_custom_css = ''; //@TODO
public $portal_custom_footer = ''; //@TODO
public $portal_custom_js = ''; //@TODO
public $client_can_register = false;
public $client_portal_terms = '';
public $client_portal_privacy_policy = '';
public $client_portal_enable_uploads = false;
public $client_portal_allow_under_payment = false;
public $client_portal_under_payment_minimum = 0;
public $client_portal_allow_over_payment = false;
public $client_can_register = false; //@implemented
public $client_portal_terms = ''; //@TODO
public $client_portal_privacy_policy = ''; //@TODO
public $client_portal_enable_uploads = false; //@implemented
public $client_portal_allow_under_payment = false; //@implemented
public $client_portal_under_payment_minimum = 0; //@implemented
public $client_portal_allow_over_payment = false; //@implemented
public $use_credits_payment = 'off'; //always, option, off
public $use_credits_payment = 'off'; //always, option, off //@implemented
public static $casts = [
'enable_reminder_endless' => 'bool',
@ -301,6 +303,9 @@ class CompanySettings extends BaseSettings
'late_fee_amount1' => 'float',
'late_fee_amount2' => 'float',
'late_fee_amount3' => 'float',
'late_fee_percent1' => 'float',
'late_fee_percent2' => 'float',
'late_fee_percent3' => 'float',
'endless_reminder_frequency_id' => 'integer',
'client_online_payment_notification' => 'bool',
'client_manual_payment_notification' => 'bool',
@ -312,7 +317,6 @@ class CompanySettings extends BaseSettings
'email_template_statement' => 'string',
'email_subject_statement' => 'string',
'signature_on_pdf' => 'bool',
// 'send_portal_password' => 'bool',
'quote_footer' => 'string',
'page_size' => 'string',
'font_size' => 'int',
@ -431,7 +435,7 @@ class CompanySettings extends BaseSettings
'auto_convert_quote' => 'bool',
'shared_invoice_quote_counter' => 'bool',
'counter_padding' => 'integer',
'design' => 'string',
//'design' => 'string',
'website' => 'string',
'pdf_variables' => 'object',
'portal_custom_head' => 'string',
@ -624,8 +628,8 @@ class CompanySettings extends BaseSettings
'task_columns' =>[
'$task.product_key',
'$task.notes',
'$task.cost',
'$task.quantity',
'$task.rate',
'$task.hours',
'$task.discount',
'$task.tax',
'$task.line_total',

View File

@ -28,7 +28,6 @@ class DefaultSettings extends BaseSettings
/**
* @return stdClass
*
* //todo user specific settings / preferences.
*/
public static function userSettings() : stdClass
{

View File

@ -178,6 +178,7 @@ class EmailTemplateDefaults
public static function emailReminder1Subject()
{
info("reminder 1 subject");
return ctrans('texts.reminder_subject', ['invoice'=>'$invoice.number', 'account'=>'$company.name']);
}

View File

@ -51,7 +51,7 @@ class InvoiceItem
public $custom_value4 = '';
public $type_id = 1; //1 = product, 2 = service, 3 unpaid gateway fee, 4 paid gateway fee
public $type_id = 1; //1 = product, 2 = service, 3 unpaid gateway fee, 4 paid gateway fee, 5 late fee
public static $casts = [
'type_id' => 'string',

View File

@ -12,6 +12,7 @@
namespace App\Events\Client;
use App\Models\Client;
use App\Models\Company;
use Illuminate\Queue\SerializesModels;
/**

View File

@ -12,6 +12,7 @@
namespace App\Events\Client;
use App\Models\Client;
use App\Models\Company;
use Illuminate\Queue\SerializesModels;
/**
@ -26,6 +27,8 @@ class ClientWasRestored
*/
public $client;
public $fromDeleted;
public $company;
public $event_vars;
@ -37,9 +40,10 @@ class ClientWasRestored
* @param Company $company
* @param array $event_vars
*/
public function __construct(Client $client, Company $company, array $event_vars)
public function __construct(Client $client, $fromDeleted, Company $company, array $event_vars)
{
$this->client = $client;
$this->fromDeleted = $fromDeleted;
$this->company = $company;
$this->event_vars = $event_vars;
}

View File

@ -12,6 +12,7 @@
namespace App\Events\Client;
use App\Models\Client;
use App\Models\Company;
use Illuminate\Queue\SerializesModels;
/**

View File

@ -11,6 +11,7 @@
namespace App\Events\Credit;
use App\Models\Company;
use App\Models\Credit;
use Illuminate\Queue\SerializesModels;
@ -30,6 +31,7 @@ class CreditWasRestored
public $event_vars;
public $fromDeleted;
/**
* Create a new event instance.
*
@ -37,9 +39,10 @@ class CreditWasRestored
* @param Company $company
* @param array $event_vars
*/
public function __construct(Credit $credit, Company $company, array $event_vars)
public function __construct(Credit $credit, $fromDeleted, Company $company, array $event_vars)
{
$this->credit = $credit;
$this->fromDeleted = $fromDeleted;
$this->company = $company;
$this->event_vars = $event_vars;
}

View File

@ -32,6 +32,7 @@ class DesignWasRestored
public $event_vars;
public $fromDeleted;
/**
* Create a new event instance.
*
@ -39,10 +40,12 @@ class DesignWasRestored
* @param Company $company
* @param array $event_vars
*/
public function __construct(Design $design, Company $company, array $event_vars)
public function __construct(Design $design, $fromDeleted, Company $company, array $event_vars)
{
$this->design = $design;
$this->fromDeleted = $fromDeleted;
$this->company = $company;
$this->event_vars = $event_vars;

View File

@ -31,6 +31,7 @@ class DocumentWasRestored
public $event_vars;
public $fromDeleted;
/**
* Create a new event instance.
*
@ -38,9 +39,10 @@ class DocumentWasRestored
* @param Company $company
* @param array $event_vars
*/
public function __construct(Document $document, Company $company, array $event_vars)
public function __construct(Document $document, $fromDeleted, Company $company, array $event_vars)
{
$this->document = $document;
$this->fromDeleted = $fromDeleted;
$this->company = $company;
$this->event_vars = $event_vars;
}

View File

@ -31,6 +31,7 @@ class ExpenseWasRestored
public $event_vars;
public $fromDeleted;
/**
* Create a new event instance.
*
@ -38,9 +39,10 @@ class ExpenseWasRestored
* @param Company $company
* @param array $event_vars
*/
public function __construct(Expense $expense, Company $company, array $event_vars)
public function __construct(Expense $expense, $fromDeleted, Company $company, array $event_vars)
{
$this->expense = $expense;
$this->fromDeleted = $fromDeleted;
$this->company = $company;
$this->event_vars = $event_vars;
}

View File

@ -0,0 +1,50 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Events\Invoice;
use App\Models\Company;
use App\Models\InvoiceInvitation;
use Illuminate\Queue\SerializesModels;
/**
* Class InvoiceReminderWasEmailed.
*/
class InvoiceReminderWasEmailed
{
use SerializesModels;
/**
* @var Invoice
*/
public $invitation;
public $reminder;
public $company;
public $event_vars;
/**
* Create a new event instance.
*
* @param InvoiceInvitation $invitation
* @param Company $company
* @param array $event_vars
*/
public function __construct(InvoiceInvitation $invitation, Company $company, array $event_vars, string $reminder)
{
$this->invitation = $invitation;
$this->company = $company;
$this->event_vars = $event_vars;
$this->reminder = $reminder;
}
}

View File

@ -32,7 +32,7 @@ class InvoiceWasRestored
public $company;
public $event_vars;
/**
* Create a new event instance.
*

View File

@ -0,0 +1,49 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Events\Product;
use App\Models\Company;
use App\Models\Invoice;
use Illuminate\Queue\SerializesModels;
/**
* Class ProductWasRestored.
*/
class ProductWasRestored
{
use SerializesModels;
/**
* @var Product
*/
public $invoice;
public $company;
public $event_vars;
public $fromDeleted;
/**
* Create a new event instance.
*
* @param Product $invoice
* @param Company $company
* @param array $event_vars
*/
public function __construct(Product $product, $fromDeleted, Company $company, array $event_vars)
{
$this->product = $product;
$this->fromDeleted = $fromDeleted;
$this->company = $company;
$this->event_vars = $event_vars;
}
}

View File

@ -12,6 +12,7 @@
namespace App\Events\Quote;
use App\Models\Company;
use App\Models\Quote;
use Illuminate\Queue\SerializesModels;
class QuoteWasArchived

View File

@ -12,6 +12,7 @@
namespace App\Events\Quote;
use App\Models\Company;
use App\Models\Quote;
use Illuminate\Queue\SerializesModels;
/**

View File

@ -12,6 +12,7 @@
namespace App\Events\Quote;
use App\Models\Company;
use App\Models\Quote;
use Illuminate\Queue\SerializesModels;
/**

View File

@ -12,6 +12,7 @@
namespace App\Events\Quote;
use App\Models\Company;
use App\Models\Quote;
use Illuminate\Queue\SerializesModels;
/**
@ -27,6 +28,7 @@ class QuoteWasRestored
public $event_vars;
public $fromDeleted;
/**
* Create a new event instance.
*
@ -34,9 +36,10 @@ class QuoteWasRestored
* @param Company $company
* @param array $event_vars
*/
public function __construct(Quote $quote, Company $company, array $event_vars)
public function __construct(Quote $quote, $fromDeleted, Company $company, array $event_vars)
{
$this->quote = $quote;
$this->fromDeleted = $fromDeleted;
$this->company = $company;
$this->event_vars = $event_vars;
}

View File

@ -31,6 +31,7 @@ class TaskWasRestored
public $event_vars;
public $fromDeleted;
/**
* Create a new event instance.
*
@ -38,9 +39,10 @@ class TaskWasRestored
* @param Company $company
* @param array $event_vars
*/
public function __construct(Task $task, Company $company, array $event_vars)
public function __construct(Task $task, $fromDeleted, Company $company, array $event_vars)
{
$this->task = $task;
$this->fromDeleted = $fromDeleted;
$this->company = $company;
$this->event_vars = $event_vars;
}

View File

@ -31,6 +31,7 @@ class VendorWasRestored
public $event_vars;
public $fromDeleted;
/**
* Create a new event instance.
*
@ -38,9 +39,10 @@ class VendorWasRestored
* @param Company $company
* @param array $event_vars
*/
public function __construct(Vendor $vendor, Company $company, array $event_vars)
public function __construct(Vendor $vendor, $fromDeleted, Company $company, array $event_vars)
{
$this->vendor = $vendor;
$this->fromDeleted = $fromDeleted;
$this->company = $company;
$this->event_vars = $event_vars;
}

View File

@ -27,6 +27,7 @@ class CloneQuoteToInvoiceFactory
unset($quote_array['hashed_id']);
unset($quote_array['invoice_id']);
unset($quote_array['id']);
unset($quote_array['invitations']);
foreach ($quote_array as $key => $value) {
$invoice->{$key} = $value;

View File

@ -25,7 +25,6 @@ class CreditFilters extends QueryFilters
* Filter based on client status.
*
* Statuses we need to handle
* //todo ?partials as a status?
* - all
* - paid
* - unpaid

View File

@ -26,7 +26,6 @@ class InvoiceFilters extends QueryFilters
* Filter based on client status.
*
* Statuses we need to handle
* //todo ?partials as a status?
* - all
* - paid
* - unpaid

View File

@ -1,5 +1,4 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*

View File

@ -1,173 +0,0 @@
<?php
namespace App\Helpers\Email;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\Quote;
use League\CommonMark\CommonMarkConverter;
class EmailBuilder
{
public $subject;
public $body;
public $recipients;
public $attachments;
public $footer;
public $template_style;
public $variables = [];
public $contact = null;
public $view_link;
public $view_text;
/**
* @param $footer
* @return $this
*/
public function setFooter($footer)
{
$this->footer = $footer;
return $this;
}
public function setVariables($variables)
{
$this->variables = $variables;
return $this;
}
/**
* @param $contact
* @return $this
*/
public function setContact($contact)
{
$this->contact = $contact;
return $this;
}
/**
* @param $subject
* @return $this
*/
public function setSubject($subject)
{
if (! empty($this->variables)) {
$subject = str_replace(array_keys($this->variables), array_values($this->variables), $subject);
}
$this->subject = $subject;
return $this;
}
/**
* @param $body
* @return $this
*/
public function setBody($body)
{
//todo move this to use HTMLEngine
if (! empty($this->variables)) {
$body = str_replace(array_keys($this->variables), array_values($this->variables), $body);
}
$this->body = $body;
return $this;
}
/**
* @param $template_style
* @return $this
*/
public function setTemplate($template_style)
{
$this->template_style = $template_style;
return $this;
}
public function setAttachments($attachments)
{
$this->attachments[] = $attachments;
return $this;
}
public function setViewLink($link)
{
$this->view_link = $link;
return $this;
}
public function setViewText($text)
{
$this->view_text = $text;
return $this;
}
/**
* @return mixed
*/
public function getSubject()
{
return $this->subject;
}
/**
* @return mixed
*/
public function getBody()
{
return $this->body;
}
/**
* @return mixed
*/
public function getRecipients()
{
return $this->recipients;
}
/**
* @return mixed
*/
public function getAttachments()
{
return $this->attachments;
}
/**
* @return mixed
*/
public function getFooter()
{
return $this->footer;
}
/**
* @return mixed
*/
public function getTemplate()
{
return $this->template_style;
}
public function getViewLink()
{
return $this->view_link;
}
public function getViewText()
{
return $this->view_text;
}
}

View File

@ -1,86 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: michael.hampton
* Date: 14/02/2020
* Time: 19:51.
*/
namespace App\Helpers\Email;
use App\Helpers\Email\EntityEmailInterface;
use App\Models\Invoice;
use App\Models\InvoiceInvitation;
use App\Utils\HtmlEngine;
use App\Utils\Number;
class InvoiceEmail extends EmailBuilder
{
public function build(InvoiceInvitation $invitation, $reminder_template = null)
{
$client = $invitation->contact->client;
$invoice = $invitation->invoice;
$contact = $invitation->contact;
if (! $reminder_template) {
$reminder_template = $invoice->calculateTemplate('invoice');
}
$body_template = $client->getSetting('email_template_'.$reminder_template);
/* Use default translations if a custom message has not been set*/
if (iconv_strlen($body_template) == 0) {
$body_template = trans(
'texts.invoice_message',
[
'invoice' => $invoice->number,
'company' => $invoice->company->present()->name(),
'amount' => Number::formatMoney($invoice->balance, $invoice->client),
],
null,
$invoice->client->locale()
);
}
$subject_template = $client->getSetting('email_subject_'.$reminder_template);
if (iconv_strlen($subject_template) == 0) {
if ($reminder_template == 'quote') {
$subject_template = trans(
'texts.quote_subject',
[
'number' => $invoice->number,
'account' => $invoice->company->present()->name(),
],
null,
$invoice->client->locale()
);
} else {
$subject_template = trans(
'texts.invoice_subject',
[
'number' => $invoice->number,
'account' => $invoice->company->present()->name(),
],
null,
$invoice->client->locale()
);
}
}
$this->setTemplate($client->getSetting('email_style'))
->setContact($contact)
->setVariables((new HtmlEngine($invitation))->makeValues())
->setSubject($subject_template)
->setBody($body_template)
->setFooter("<a href='{$invitation->getLink()}'>".ctrans('texts.view_invoice').'</a>')
->setViewLink($invitation->getLink())
->setViewText(ctrans('texts.view_invoice'));
if ($client->getSetting('pdf_email_attachment') !== false) {
$this->setAttachments($invitation->pdf_file_path());
}
return $this;
}
}

View File

@ -1,48 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: michael.hampton
* Date: 14/02/2020
* Time: 19:51.
*/
namespace App\Helpers\Email;
use App\Models\Payment;
class PaymentEmail extends EmailBuilder
{
public function build(Payment $payment, $contact = null)
{
$client = $payment->client;
$body_template = $client->getSetting('email_template_payment');
/* Use default translations if a custom message has not been set*/
if (iconv_strlen($body_template) == 0) {
$body_template = trans(
'texts.payment_message',
['amount' => $payment->amount, 'company' => $payment->company->present()->name()],
null,
$this->client->locale()
);
}
$subject_template = $client->getSetting('email_subject_payment');
if (iconv_strlen($subject_template) == 0) {
$subject_template = trans(
'texts.payment_subject',
['number' => $payment->number, 'company' => $payment->company->present()->name()],
null,
$payment->client->locale()
);
}
$this->setTemplate($payment->client->getSetting('email_style'))
->setSubject($subject_template)
->setBody($body_template);
return $this;
}
}

View File

@ -1,70 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: michael.hampton
* Date: 14/02/2020
* Time: 19:51.
*/
namespace App\Helpers\Email;
use App\Models\Quote;
use App\Models\QuoteInvitation;
use App\Utils\HtmlEngine;
class QuoteEmail extends EmailBuilder
{
public function build(QuoteInvitation $invitation, $reminder_template)
{
$client = $invitation->contact->client;
$quote = $invitation->quote;
$contact = $invitation->contact;
$this->template_style = $client->getSetting('email_style');
$body_template = $client->getSetting('email_template_'.$reminder_template);
/* Use default translations if a custom message has not been set*/
if (iconv_strlen($body_template) == 0) {
$body_template = trans(
'texts.quote_message',
['amount' => $quote->amount, 'company' => $quote->company->present()->name()],
null,
$quote->client->locale()
);
}
$subject_template = $client->getSetting('email_subject_'.$reminder_template);
if (iconv_strlen($subject_template) == 0) {
if ($reminder_template == 'quote') {
$subject_template = trans(
'texts.quote_subject',
['number' => $quote->number, 'company' => $quote->company->present()->name()],
null,
$quote->client->locale()
);
} else {
$subject_template = trans(
'texts.reminder_subject',
['number' => $quote->number, 'company' => $quote->company->present()->name()],
null,
$quote->client->locale()
);
}
}
$this->setTemplate($quote->client->getSetting('email_style'))
->setContact($contact)
->setFooter("<a href='{$invitation->getLink()}'>Quote Link</a>")
->setVariables((new HtmlEngine($invitation))->makeValues())
->setSubject($subject_template)
->setBody($body_template);
if ($client->getSetting('pdf_email_attachment') !== false) {
$this->attachments = $invitation->pdf_file_path();
}
return $this;
}
}

View File

@ -1,4 +1,13 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Helpers\Language;

View File

@ -63,7 +63,7 @@ class GmailTransport extends Transport
$this->gmail->cc($message->getCc());
$this->gmail->bcc($message->getBcc());
Log::error(print_r($message->getChildren(), 1));
info(print_r($message->getChildren(), 1));
foreach ($message->getChildren() as $child) {
$this->gmail->attach($child);

View File

@ -22,7 +22,5 @@
*/
function ctrans(string $string, $replace = [], $locale = null) : string
{
//todo pass through the cached version of the custom strings here else return trans();
return trans($string, $replace, $locale);
}

View File

@ -13,6 +13,7 @@ namespace App\Http\Controllers;
use App\DataMapper\ClientSettings;
use App\Events\Client\ClientWasCreated;
use App\Events\Client\ClientWasUpdated;
use App\Factory\ClientFactory;
use App\Filters\ClientFilters;
use App\Http\Requests\Client\BulkClientRequest;
@ -288,6 +289,8 @@ class ClientController extends BaseController
$this->uploadLogo($request->file('company_logo'), $client->company, $client);
event(new ClientWasUpdated($client, $client->company, Ninja::eventVars()));
return $this->itemResponse($client->fresh());
}

View File

@ -40,7 +40,7 @@ class InvitationController extends Controller
$key = $entity.'_id';
$entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation'; //todo sensitive to the route parameters here
$entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation';
$invitation = $entity_obj::whereRaw('BINARY `key`= ?', [$invitation_key])
->with('contact.client')

View File

@ -218,8 +218,9 @@ class PaymentController extends Controller
'amount_with_fee' => $invoice_totals + $fee_totals,
];
if($is_credit_payment)
if($is_credit_payment) {
return $this->processCreditPayment($request, $data);
}
return $gateway
->driver(auth()->user()->client)

View File

@ -109,8 +109,8 @@ class QuoteController extends Controller
if ($process) {
foreach ($quotes as $quote) {
$quote->service()->approve()->save();
event(new QuoteWasApproved(auth()->user(), $quote, $quote->company, Ninja::eventVars()));
$quote->service()->approve(auth()->user())->save();
event(new QuoteWasApproved(auth('contact')->user(), $quote, $quote->company, Ninja::eventVars()));
}
return redirect()

View File

@ -408,6 +408,10 @@ class CompanyController extends BaseController
*/
public function update(UpdateCompanyRequest $request, Company $company)
{
if($request->hasFile('company_logo') || (is_array($request->input('settings')) && !array_key_exists('company_logo', $request->input('settings'))))
$this->removeLogo($company);
$company = $this->company_repo->save($request->all(), $company);
$company->saveSettings($request->input('settings'), $company);

View File

@ -16,7 +16,6 @@ use App\Http\Requests\Credit\ShowCreditRequest;
use App\Http\Requests\Credit\StoreCreditRequest;
use App\Http\Requests\Credit\UpdateCreditRequest;
use App\Http\Requests\Invoice\EditInvoiceRequest;
use App\Jobs\Credit\StoreCredit;
use App\Jobs\Entity\EmailEntity;
use App\Jobs\Invoice\EmailCredit;
use App\Jobs\Invoice\MarkInvoicePaid;
@ -188,7 +187,9 @@ class CreditController extends BaseController
$credit = $this->credit_repository->save($request->all(), CreditFactory::create(auth()->user()->company()->id, auth()->user()->id));
$credit = StoreCredit::dispatchNow($credit, $request->all(), $credit->company);
$credit = $credit->service()
->fillDefaults()
->save();
event(new CreditWasCreated($credit, $credit->company, Ninja::eventVars()));
@ -553,7 +554,7 @@ class CreditController extends BaseController
// EmailCredit::dispatch($credit, $credit->company);
$credit->invitations->load('contact.client.country', 'credit.client.country', 'credit.company')->each(function ($invitation) use ($credit) {
EmailEntity::dispatch($invitation, $credit->company);
EmailEntity::dispatch($invitation, $credit->company, 'credit');
});
@ -571,10 +572,10 @@ class CreditController extends BaseController
public function downloadPdf($invitation_key)
{
$invitation = $this->credit_repository->getInvitationByKey($invitation_key);
$contact = $invitation->contact;
// $contact = $invitation->contact;
$credit = $invitation->credit;
$file_path = $credit->service()->getCreditPdf($contact);
$file_path = $credit->service()->getCreditPdf($invitation);
return response()->download($file_path);
}

View File

@ -11,7 +11,6 @@
namespace App\Http\Controllers;
use App\Helpers\Email\InvoiceEmail;
use App\Http\Requests\Email\SendEmailRequest;
use App\Jobs\Entity\EmailEntity;
use App\Jobs\Invoice\EmailInvoice;
@ -117,22 +116,30 @@ class EmailController extends BaseController
$subject = $request->input('subject');
$body = $request->input('body');
$entity_string = strtolower(class_basename($entity_obj));
$template = $request->input('template');
$template = str_replace("email_template_", "", $template);
$entity_obj->invitations->each(function ($invitation) use ($subject, $body, $entity_string, $entity_obj, $template) {
$entity_obj->invitations->each(function ($invitation) use ($subject, $body, $entity_string, $entity_obj) {
if ($invitation->contact->send_email && $invitation->contact->email) {
EmailEntity::dispatchNow($invitation, $invitation->company);
//$invitation->contact->notify((new SendGenericNotification($invitation, $entity_string, $subject, $body))->delay($when));
$data = [
'subject' => $subject,
'body' => $body
];
EmailEntity::dispatchNow($invitation, $invitation->company, $template, $data);
}
});
$entity_obj->last_sent_date = now();
$entity_obj->save();
/*Only notify the admin ONCE, not once per contact/invite*/
$invitation = $entity_obj->invitations->first();
EntitySentMailer::dispatch($invitation, $entity_string, $entity_obj->user, $invitation->company);
// $invitation = $entity_obj->invitations->first();
// EntitySentMailer::dispatch($invitation, $entity_string, $entity_obj->user, $invitation->company);
if ($entity_obj instanceof Invoice) {
$this->entity_type = Invoice::class;

View File

@ -11,6 +11,8 @@
namespace App\Http\Controllers;
use App\Events\Expense\ExpenseWasCreated;
use App\Events\Expense\ExpenseWasUpdated;
use App\Factory\ExpenseFactory;
use App\Filters\ExpenseFilters;
use App\Http\Requests\Expense\CreateExpenseRequest;
@ -29,6 +31,7 @@ use App\Models\Size;
use App\Repositories\BaseRepository;
use App\Repositories\ExpenseRepository;
use App\Transformers\ExpenseTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\BulkOptions;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Uploadable;
@ -281,6 +284,8 @@ class ExpenseController extends BaseController
$this->uploadLogo($request->file('company_logo'), $expense->company, $expense);
event(new ExpenseWasUpdated($expense, $expense->company, Ninja::eventVars()));
return $this->itemResponse($expense->fresh());
}
@ -373,6 +378,8 @@ class ExpenseController extends BaseController
{
$expense = $this->expense_repo->save($request->all(), ExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id));
event(new ExpenseWasCreated($expense, $expense->company, Ninja::eventVars()));
return $this->itemResponse($expense);
}

View File

@ -20,7 +20,6 @@ use App\Factory\CloneInvoiceFactory;
use App\Factory\CloneInvoiceToQuoteFactory;
use App\Factory\InvoiceFactory;
use App\Filters\InvoiceFilters;
use App\Helpers\Email\InvoiceEmail;
use App\Http\Requests\Invoice\ActionInvoiceRequest;
use App\Http\Requests\Invoice\CreateInvoiceRequest;
use App\Http\Requests\Invoice\DestroyInvoiceRequest;
@ -35,8 +34,10 @@ use App\Jobs\Util\UnlinkFile;
use App\Models\Client;
use App\Models\Invoice;
use App\Models\InvoiceInvitation;
use App\Models\Quote;
use App\Repositories\InvoiceRepository;
use App\Transformers\InvoiceTransformer;
use App\Transformers\QuoteTransformer;
use App\Utils\Ninja;
use App\Utils\TempFile;
use App\Utils\Traits\MakesHash;
@ -213,7 +214,10 @@ class InvoiceController extends BaseController
event(new InvoiceWasCreated($invoice, $invoice->company, Ninja::eventVars()));
$invoice = $invoice->service()->triggeredActions($request)->save();
$invoice = $invoice->service()
->fillDefaults()
->triggeredActions($request)
->save();
return $this->itemResponse($invoice);
}
@ -637,7 +641,12 @@ class InvoiceController extends BaseController
break;
case 'clone_to_quote':
$quote = CloneInvoiceToQuoteFactory::create($invoice, auth()->user()->id);
// todo build the quote transformer and return response here
$this->entity_transformer = QuoteTransformer::class;
$this->entity_type = Quote::class;
return $this->itemResponse($quote);
break;
case 'history':
// code...
@ -720,9 +729,8 @@ class InvoiceController extends BaseController
$invoice->service()->touchReminder($this->reminder_template)->save();
$invoice->invitations->load('contact.client.country', 'invoice.client.country', 'invoice.company')->each(function ($invitation) use ($invoice) {
$email_builder = (new InvoiceEmail())->build($invitation, $this->reminder_template);
EmailEntity::dispatch($invitation, $invoice->company);
EmailEntity::dispatch($invitation, $invoice->company, $this->reminder_template);
});
if (! $bulk) {
@ -790,4 +798,57 @@ class InvoiceController extends BaseController
return response()->download($file_path, basename($file_path));
}
/**
* @OA\Get(
* path="/api/v1/invoices/{id}/delivery_note",
* operationId="deliveryNote",
* tags={"invoices"},
* summary="Download a specific invoice delivery notes",
* description="Downloads a specific invoice delivery notes",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Invoice Hahsed Id",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the invoice delivery note pdf",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
* @param $invoice
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
*/
public function deliveryNote(ShowInvoiceRequest $request, Invoice $invoice)
{
$file_path = $invoice->service()->getInvoiceDeliveryNote($invoice, $invoice->invitations->first()->contact);
$file = base_path("storage/app/public/{$file_path}");
return response()->download($file, basename($file));
}
}

View File

@ -7,8 +7,8 @@
* @OA\Property(property="company_id", type="string", example="2", description="______"),
* @OA\Property(property="gateway_key", type="string", example="2", description="______"),
* @OA\Property(property="accepted_credit_cards", type="integer", example="32", description="Bitmask representation of cards"),
* @OA\Property(property="show_billing_address", type="boolean", example=true, description="______"),
* @OA\Property(property="show_shipping_address", type="boolean", example=true, description="______"),
* @OA\Property(property="require_billing_address", type="boolean", example=true, description="______"),
* @OA\Property(property="require_shipping_address", type="boolean", example=true, description="______"),
* @OA\Property(property="config", type="string", example="dfadsfdsafsafd", description="The configuration map for the gateway"),
* @OA\Property(property="update_details", type="boolean", example=true, description="______"),
* @OA\Property(

View File

@ -12,15 +12,15 @@
* @OA\License(
* name="Attribution Assurance License",
* url="https://opensource.org/licenses/AAL"
* )
* ),
* ),
* @OA\Server(
* description="Example InvoiceNinja base url",
* url="https://ninja.test"
* url="https://ninja.test",
* ),
* @OA\ExternalDocumentation(
* description="http://docs.invoiceninja.com",
* url="http://docs.invoiceninja.com"
* )
* )
* ),
* ),
*/

View File

@ -29,8 +29,10 @@ use App\Repositories\BaseRepository;
use App\Repositories\PaymentRepository;
use App\Transformers\PaymentTransformer;
use App\Utils\Traits\MakesHash;
use App\Events\Payment\PaymentWasUpdated;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Utils\Ninja;
/**
* Class PaymentController.
@ -379,6 +381,7 @@ class PaymentController extends BaseController
$payment = $this->payment_repo->save($request->all(), $payment);
event(new PaymentWasUpdated($payment, $payment->company, Ninja::eventVars()));
return $this->itemResponse($payment);
}
@ -506,7 +509,7 @@ class PaymentController extends BaseController
$payments->each(function ($payment, $key) use ($action) {
if (auth()->user()->can('edit', $payment)) {
$this->payment_repo->{$action}($payment);
$this->performAction($payment, $action, true);
}
});
@ -584,30 +587,31 @@ class PaymentController extends BaseController
* @param Payment $payment
* @param $action
*/
public function action(ActionPaymentRequest $request, Payment $payment, $action)
public function performAction(Payment $payment, $action, $bulk = false)
{
switch ($action) {
case 'clone_to_invoice':
//$payment = CloneInvoiceFactory::create($payment, auth()->user()->id);
//return $this->itemResponse($payment);
break;
case 'clone_to_quote':
//$quote = CloneInvoiceToQuoteFactory::create($payment, auth()->user()->id);
// todo build the quote transformer and return response here
break;
case 'history':
// code...
break;
case 'delivery_note':
// code...
break;
case 'mark_paid':
// code...
case 'restore':
$this->payment_repo->restore($payment);
if (! $bulk) {
return $this->listResponse($payment);
}
break;
case 'archive':
$this->payment_repo->archive($payment);
if (! $bulk) {
return $this->listResponse($payment);
}
// code...
break;
case 'delete':
$this->payment_repo->delete($payment);
if (! $bulk) {
return $this->listResponse($payment);
}
// code...
break;
case 'email':

View File

@ -11,6 +11,8 @@
namespace App\Http\Controllers;
use App\Events\Quote\QuoteWasCreated;
use App\Events\Quote\QuoteWasUpdated;
use App\Factory\CloneInvoiceFactory;
use App\Factory\CloneInvoiceToQuoteFactory;
use App\Factory\CloneQuoteFactory;
@ -31,6 +33,7 @@ use App\Models\Quote;
use App\Repositories\QuoteRepository;
use App\Transformers\InvoiceTransformer;
use App\Transformers\QuoteTransformer;
use App\Utils\Ninja;
use App\Utils\TempFile;
use App\Utils\Traits\MakesHash;
use Illuminate\Http\Request;
@ -79,8 +82,8 @@ class QuoteController extends BaseController
* tags={"quotes"},
* summary="Gets a list of quotes",
* description="Lists quotes, search and filters allow fine grained lists to be generated.
Query parameters can be added to performed more fine grained filtering of the quotes, these are handled by the QuoteFilters class which defines the methods available",
*
* Query parameters can be added to performed more fine grained filtering of the quotes, these are handled by the QuoteFilters class which defines the methods available",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
@ -204,6 +207,10 @@ class QuoteController extends BaseController
$quote = $this->quote_repo->save($request->all(), QuoteFactory::create(auth()->user()->company()->id, auth()->user()->id));
$quote = $quote->service()->fillDefaults()->save();
event(new QuoteWasCreated($quote, $quote->company, Ninja::eventVars()));
return $this->itemResponse($quote);
}
@ -378,6 +385,8 @@ class QuoteController extends BaseController
$quote = $this->quote_repo->save($request->all(), $quote);
event(new QuoteWasUpdated($quote, $quote->company, Ninja::eventVars()));
return $this->itemResponse($quote);
}
@ -658,15 +667,26 @@ class QuoteController extends BaseController
}, basename($quote->pdf_file_path()));
//return response()->download(TempFile::path($quote->pdf_file_path()), basename($quote->pdf_file_path()));
break;
case 'restore':
$this->quote_repo->restore($quote);
if (!$bulk)
return $this->listResponse($quote);
break;
case 'archive':
$this->quote_repo->archive($quote);
return $this->listResponse($quote);
if (!$bulk)
return $this->listResponse($quote);
break;
case 'delete':
$this->quote_repo->delete($quote);
return $this->listResponse($quote);
if (!$bulk)
return $this->listResponse($quote);
break;
case 'email':
$quote->service()->sendEmail();
@ -679,6 +699,7 @@ class QuoteController extends BaseController
if (! $bulk) {
return $this->itemResponse($quote);
}
break;
// no break
default:
return response()->json(['message' => "The requested action `{$action}` is not available."], 400);

View File

@ -23,9 +23,11 @@ use App\Http\Requests\RecurringQuote\ShowRecurringQuoteRequest;
use App\Http\Requests\RecurringQuote\StoreRecurringQuoteRequest;
use App\Http\Requests\RecurringQuote\UpdateRecurringQuoteRequest;
use App\Jobs\Entity\ActionEntity;
use App\Models\Quote;
use App\Models\RecurringQuote;
use App\Repositories\BaseRepository;
use App\Repositories\RecurringQuoteRepository;
use App\Transformers\QuoteTransformer;
use App\Transformers\RecurringQuoteTransformer;
use App\Utils\Traits\MakesHash;
use Illuminate\Http\Request;
@ -583,8 +585,11 @@ class RecurringQuoteController extends BaseController
// return $this->itemResponse($recurring_invoice);
break;
case 'clone_to_quote':
// $quote = CloneRecurringQuoteToQuoteFactory::create($recurring_invoice, auth()->user()->id);
// todo build the quote transformer and return response here
$quote = CloneRecurringQuoteToQuoteFactory::create($recurring_invoice, auth()->user()->id);
$this->entity_transformer = QuoteTransformer::class;
$this->entity_type = Quote::class;
return $this->itemResponse($quote);
break;
case 'history':
// code...

View File

@ -84,4 +84,9 @@ class SelfUpdateController extends BaseController
return response()->json(['message' => ''], 200);
}
public function checkVersion()
{
return trim(file_get_contents(config('ninja.version_url')));
}
}

View File

@ -11,6 +11,8 @@
namespace App\Http\Controllers;
use App\Events\Task\TaskWasCreated;
use App\Events\Task\TaskWasUpdated;
use App\Factory\TaskFactory;
use App\Filters\TaskFilters;
use App\Http\Requests\Task\CreateTaskRequest;
@ -24,11 +26,12 @@ use App\Jobs\Util\ProcessBulk;
use App\Jobs\Util\UploadAvatar;
use App\Models\Country;
use App\Models\Currency;
use App\Models\Task;
use App\Models\Size;
use App\Models\Task;
use App\Repositories\BaseRepository;
use App\Repositories\TaskRepository;
use App\Transformers\TaskTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\BulkOptions;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Uploadable;
@ -278,6 +281,8 @@ class TaskController extends BaseController
$task = $this->task_repo->save($request->all(), $task);
event(new TaskWasUpdated($task, $task->company, Ninja::eventVars()));
return $this->itemResponse($task->fresh());
}
@ -370,6 +375,8 @@ class TaskController extends BaseController
{
$task = $this->task_repo->save($request->all(), TaskFactory::create(auth()->user()->company()->id, auth()->user()->id));
event(new TaskWasCreated($task, $task->company, Ninja::eventVars()));
return $this->itemResponse($task);
}

View File

@ -11,6 +11,8 @@
namespace App\Http\Controllers;
use App\Events\Vendor\VendorWasCreated;
use App\Events\Vendor\VendorWasUpdated;
use App\Factory\VendorFactory;
use App\Filters\VendorFilters;
use App\Http\Requests\Vendor\CreateVendorRequest;
@ -29,6 +31,7 @@ use App\Models\Vendor;
use App\Repositories\BaseRepository;
use App\Repositories\VendorRepository;
use App\Transformers\VendorTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\BulkOptions;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Uploadable;
@ -280,6 +283,8 @@ class VendorController extends BaseController
$this->uploadLogo($request->file('company_logo'), $vendor->company, $vendor);
event(new VendorWasUpdated($vendor, $vendor->company, Ninja::eventVars()));
return $this->itemResponse($vendor->fresh());
}
@ -376,6 +381,8 @@ class VendorController extends BaseController
$this->uploadLogo($request->file('company_logo'), $vendor->company, $vendor);
event(new VendorWasCreated($vendor, $vendor->company, Ninja::eventVars()));
return $this->itemResponse($vendor);
}

View File

@ -380,7 +380,7 @@ class WebhookController extends BaseController
*
* @throws \Exception
* @OA\Delete(
* path="/api/v1/Webhooks/{id}",
* path="/api/v1/webhooks/{id}",
* operationId="deleteWebhook",
* tags={"Webhooks"},
* summary="Deletes a Webhook",

View File

@ -55,7 +55,7 @@ class ContactTokenAuth
//stateless, don't remember the contact.
auth()->guard('contact')->login($client_contact, false);
event(new ContactLoggedIn($client_contact, $client_contact->company, Ninja::eventVars())); //todo
event(new ContactLoggedIn($client_contact, $client_contact->company, Ninja::eventVars()));
} else {
$error = [
'message' => 'Invalid token',

View File

@ -75,7 +75,7 @@ class StoreClientRequest extends Request
$input = $this->all();
//@todo implement feature permissions for > 100 clients
//
$settings = ClientSettings::defaults();
if (array_key_exists('settings', $input) && ! empty($input['settings'])) {

View File

@ -28,7 +28,7 @@ class ShowDocumentRequest extends FormRequest
*/
public function authorize()
{
return auth()->user('contact')->client->id === $this->document->documentable->id;
return auth()->user('contact')->client->id == $this->document->documentable_id;
}
/**

View File

@ -77,7 +77,7 @@ class StorePaymentRequest extends Request
}
if (! isset($input['amount']) || $input['amount'] == 0) {
$input['amount'] = $invoices_total - $credits_total; //todo the payment amount is always less the credit amount applied
$input['amount'] = $invoices_total - $credits_total;
}
$input['is_manual'] = true;

View File

@ -109,22 +109,20 @@ class StoreRecurringInvoiceRequest extends Request
}
$this->replace($input);
}
private function setAutoBillFlag($auto_bill)
{
if($auto_bill == 'always')
return true;
if($auto_bill == 'off')
return false;
//todo do we need to handle optin / optout here?
}
public function messages()
{
return [];
}
private function setAutoBillFlag($auto_bill)
{
if($auto_bill == 'always')
return true;
if($auto_bill == 'off')
return false;
}
public function messages()
{
return [];
}
}

View File

@ -46,16 +46,28 @@ class ValidCreditsPresentRule implements Rule
{
//todo need to ensure the clients credits are here not random ones!
if (request()->input('credits') && is_array(request()->input('credits'))) {
foreach (request()->input('credits') as $credit) {
$cred = Credit::find($this->decodePrimaryKey($credit['credit_id']));
// if (request()->input('credits') && is_array(request()->input('credits'))) {
// foreach (request()->input('credits') as $credit) {
// $cred = Credit::find($this->decodePrimaryKey($credit['credit_id']));
if (! $cred || $cred->balance == 0) {
return false;
}
}
// if (! $cred || $cred->balance == 0) {
// return false;
// }
// }
// }
// return true;
if (request()->input('credits') && is_array(request()->input('credits'))) {
$credit_collection = Credit::whereIn('id', $this->transformKeys(array_column(request()->input('credits'), 'credit_id')))
->where('balance', '>', 0)
->get();
return $credit_collection->count() == count(request()->input('credits'));
}
return true;
return true;
}
}

View File

@ -12,7 +12,9 @@
namespace App\Http\ViewComposers;
use App\Models\ClientContact;
use App\Utils\Ninja;
use App\Utils\TranslationHelper;
use Illuminate\Support\Facades\Lang;
use Illuminate\View\View;
/**
@ -29,6 +31,9 @@ class PortalComposer
public function compose(View $view) :void
{
$view->with($this->portalData());
if(auth()->user())
Lang::replace(Ninja::transformTranslations(auth()->user()->client->getMergedSettings()));
}
/**

View File

@ -1,55 +0,0 @@
<?php
namespace App\Jobs\Credit;
use App\Jobs\Payment\PaymentNotification;
use App\Libraries\MultiDB;
use App\Models\Company;
use App\Models\Credit;
use App\Repositories\CreditRepository;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class StoreCredit implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $credit;
protected $data;
/**
* Create a new job instance.
*
* @param Credit $credit
* @param array $data
*/
public function __construct(Credit $credit, array $data)
{
$this->credit = $credit;
$this->data = $data;
}
/**
* Execute the job.
*
* @param CreditRepository $credit_repository
* @return Credit|null
*/
public function handle(CreditRepository $credit_repository): ?Credit
{
// MultiDB::setDB($this->company->db);
// $payment = false;
// if ($payment) {
// PaymentNotification::dispatch($payment, $payment->company);
// }
return $this->credit;
}
}

View File

@ -31,6 +31,7 @@ use App\Services\PdfMaker\Design as PdfDesignModel;
use App\Services\PdfMaker\Design as PdfMakerDesign;
use App\Services\PdfMaker\PdfMaker as PdfMakerService;
use App\Utils\HtmlEngine;
use App\Utils\Ninja;
use App\Utils\PhantomJS\Phantom;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\MakesInvoiceHtml;
@ -42,6 +43,7 @@ use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Storage;
use Spatie\Browsershot\Browsershot;
@ -102,6 +104,7 @@ class CreateEntityPdf implements ShouldQueue
}
App::setLocale($this->contact->preferredLocale());
App::forgetInstance('translator');
$entity_design_id = '';
@ -118,6 +121,8 @@ class CreateEntityPdf implements ShouldQueue
$entity_design_id = 'credit_design_id';
}
Lang::replace(Ninja::transformTranslations($this->entity->client->getMergedSettings()));
$file_path = $path.$this->entity->number.'.pdf';
$entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->entity->client->getSetting($entity_design_id));
@ -139,7 +144,7 @@ class CreateEntityPdf implements ShouldQueue
'client' => $this->entity->client,
'entity' => $this->entity,
'pdf_variables' => (array) $this->entity->company->settings->pdf_variables,
'products' => $design->design->product,
'$product' => $design->design->product,
]),
'variables' => $html->generateLabelsAndValues(),
'options' => [

View File

@ -12,13 +12,14 @@
namespace App\Jobs\Entity;
use App\DataMapper\Analytics\EmailInvoiceFailure;
use App\Events\Invoice\InvoiceReminderWasEmailed;
use App\Events\Invoice\InvoiceWasEmailed;
use App\Events\Invoice\InvoiceWasEmailedAndFailed;
use App\Helpers\Email\InvoiceEmail;
use App\Jobs\Mail\BaseMailerJob;
use App\Jobs\Utils\SystemLogger;
use App\Libraries\MultiDB;
use App\Mail\TemplateEmail;
use App\Models\Activity;
use App\Models\Company;
use App\Models\CreditInvitation;
use App\Models\Invoice;
@ -61,13 +62,14 @@ class EmailEntity extends BaseMailerJob implements ShouldQueue
public $email_entity_builder;
public $template_data;
/**
* EmailEntity constructor.
* @param Invitation $invitation
* @param Company $company
* @param ?string $reminder_template
*/
public function __construct($invitation, Company $company, ?string $reminder_template = null)
public function __construct($invitation, Company $company, ?string $reminder_template = null, $template_data = null)
{
$this->company = $company;
@ -79,11 +81,14 @@ class EmailEntity extends BaseMailerJob implements ShouldQueue
$this->entity = $invitation->{$this->entity_string};
$this->reminder_template = $reminder_template ?: $this->findReminderTemplate();
$this->reminder_template = $reminder_template ?: $this->entity->calculateTemplate($this->entity_string);
$this->html_engine = new HtmlEngine($invitation);
$this->template_data = $template_data;
$this->email_entity_builder = $this->resolveEmailBuilder();
}
/**
@ -166,26 +171,32 @@ class EmailEntity extends BaseMailerJob implements ShouldQueue
private function entityEmailSucceeded()
{
switch ($this->entity_string) {
switch ($this->reminder_template) {
case 'invoice':
event(new InvoiceWasEmailed($this->invitation, $this->company, Ninja::eventVars()));
break;
case 'reminder1':
event(new InvoiceReminderWasEmailed($this->invitation, $this->company, Ninja::eventVars(), Activity::INVOICE_REMINDER1_SENT));
break;
case 'reminder2':
event(new InvoiceReminderWasEmailed($this->invitation, $this->company, Ninja::eventVars(), Activity::INVOICE_REMINDER2_SENT));
break;
case 'reminder3':
event(new InvoiceReminderWasEmailed($this->invitation, $this->company, Ninja::eventVars(), Activity::INVOICE_REMINDER3_SENT));
break;
case 'reminder_endless':
event(new InvoiceReminderWasEmailed($this->invitation, $this->company, Ninja::eventVars(), Activity::INVOICE_REMINDER_ENDLESS_SENT));
break;
default:
# code...
break;
}
}
private function findReminderTemplate()
{
}
private function resolveEmailBuilder()
{
$class = 'App\Mail\Engine\\' . ucfirst(Str::camel($this->entity_string)) . "EmailEngine";
return (new $class($this->invitation, $this->reminder_template))->build();
return (new $class($this->invitation, $this->reminder_template, $this->template_data))->build();
}
}

View File

@ -16,12 +16,15 @@ use App\Libraries\Google\Google;
use App\Libraries\MultiDB;
use App\Models\User;
use App\Providers\MailServiceProvider;
use App\Utils\Ninja;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Lang;
use Turbo124\Beacon\Facades\LightLogs;
/*Multi Mailer implemented*/
@ -32,6 +35,9 @@ class BaseMailerJob implements ShouldQueue
public function setMailDriver()
{
App::forgetInstance('translator');
Lang::replace(Ninja::transformTranslations($this->settings));
switch ($this->settings->email_sending_method) {
case 'default':
break;
@ -69,7 +75,7 @@ class BaseMailerJob implements ShouldQueue
}
public function logMailError($errors, $recipient_object)
{
{info(print_r($errors,1));
SystemLogger::dispatch(
$errors,
SystemLog::CATEGORY_MAIL,

View File

@ -53,11 +53,11 @@ class EntityPaidMailer extends BaseMailerJob implements ShouldQueue
* @param $user
* @param $company
*/
public function __construct($payment, $company)
public function __construct($payment, $company, $user)
{
$this->company = $company;
$this->user = $payment->user;
$this->user = $user;
$this->payment = $payment;
@ -84,7 +84,7 @@ class EntityPaidMailer extends BaseMailerJob implements ShouldQueue
try {
$mail_obj = (new EntityPaidObject($this->payment))->build();
$mail_obj->from = [$this->payment->user->email, $this->payment->user->present()->name()];
$mail_obj->from = [$this->user->email, $this->user->present()->name()];
//send email
Mail::to($this->user->email)
@ -96,7 +96,7 @@ class EntityPaidMailer extends BaseMailerJob implements ShouldQueue
}
if (count(Mail::failures()) > 0) {
$this->logMailError(Mail::failures(), $this->entity->client);
$this->logMailError(Mail::failures(), $this->payment->client);
} else {
// $this->entityEmailSucceeded();
}

View File

@ -11,7 +11,6 @@
namespace App\Jobs\Ninja;
use App\Helpers\Email\InvoiceEmail;
use App\Jobs\Invoice\EmailInvoice;
use App\Libraries\MultiDB;
use App\Models\Account;

View File

@ -11,7 +11,6 @@
namespace App\Jobs\Ninja;
use App\Helpers\Email\InvoiceEmail;
use App\Jobs\Invoice\EmailInvoice;
use App\Libraries\MultiDB;
use App\Models\Account;

View File

@ -11,7 +11,6 @@
namespace App\Jobs\Ninja;
use App\Helpers\Email\InvoiceEmail;
use App\Jobs\Invoice\EmailInvoice;
use App\Libraries\MultiDB;
use App\Models\Account;

View File

@ -0,0 +1,327 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Ninja;
use App\DataMapper\InvoiceItem;
use App\Events\Invoice\InvoiceWasEmailed;
use App\Jobs\Entity\EmailEntity;
use App\Libraries\MultiDB;
use App\Models\Invoice;
use App\Utils\Ninja;
use App\Utils\Traits\MakesDates;
use App\Utils\Traits\MakesReminders;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Carbon;
class SendReminders implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesDates, MakesReminders;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
info("Sending reminders ".Carbon::now()->format('Y-m-d h:i:s'));
if (! config('ninja.db.multi_db_enabled')) {
$this->sendReminderEmails();
} else {
//multiDB environment, need to
foreach (MultiDB::$dbs as $db)
{
MultiDB::setDB($db);
$this->sendReminderEmails();
}
}
}
private function sendReminderEmails()
{
$invoices = Invoice::where('is_deleted', 0)
->where('balance', '>', 0)
->whereDate('next_send_date', '<=', now()->startOfDay())
->whereNotNull('next_send_date')
->with('client')
->cursor();
//we only need invoices that are payable
$invoices->filter(function ($invoice){
return $invoice->isPayable();
})->each(function ($invoice){
$reminder_template = $invoice->calculateTemplate('invoice');
info("hitting a reminder for {$invoice->number} with template {$reminder_template}");
if(in_array($reminder_template, ['reminder1', 'reminder2', 'reminder3', 'endless_reminder']))
$this->sendReminder($invoice, $reminder_template);
});
}
private function checkSendSetting($invoice, $template)
{
switch ($template) {
case 'reminder1':
return $invoice->client->getSetting('enable_reminder1');
break;
case 'reminder2':
return $invoice->client->getSetting('enable_reminder2');
break;
case 'reminder3':
return $invoice->client->getSetting('enable_reminder3');
break;
case 'endless_reminder':
return $invoice->client->getSetting('enable_reminder_endless');
break;
default:
return false;
break;
}
}
/**
* Create a collection of all possible reminder dates
* and pass back the first one in chronology
*
* @param Invoice $invoice
* @return Carbon $date
*/
private function calculateNextSendDate($invoice)
{
$dates = collect();
$settings = $invoice->client->getMergedSettings();
$set_reminder1 = false;
$set_reminder2 = false;
$set_reminder3 = false;
if((int)$settings->schedule_reminder1 > 0){
$next_reminder_date = $this->calculateScheduledDate($invoice, (int)$settings->schedule_reminder1, (int)$settings->num_days_reminder1);
if($next_reminder_date->gt(Carbon::parse($invoice->last_sent_date)));
$dates->push($next_reminder_date);
if(!$invoice->reminder1_sent)
$set_reminder1 = true;
}
if((int)$settings->num_days_reminder2 > 0){
$next_reminder_date = $this->calculateScheduledDate($invoice, (int)$settings->schedule_reminder2, (int)$settings->num_days_reminder2);
if($next_reminder_date->gt(Carbon::parse($invoice->last_sent_date)));
$dates->push($next_reminder_date);
if(!$invoice->reminder2_sent)
$set_reminder3 = true;
}
if((int)$settings->num_days_reminder3 > 0){
$next_reminder_date = $this->calculateScheduledDate($invoice, (int)$settings->schedule_reminder3, (int)$settings->num_days_reminder3);
if($next_reminder_date->gt(Carbon::parse($invoice->last_sent_date)));
$dates->push($next_reminder_date);
if(!$invoice->reminder3_sent)
$set_reminder3 = true;
}
//If all the available reminders have fired, we then start to fire the endless reminders
if((int)$settings->endless_reminder_frequency_id > 0 && !$set_reminder1 && !$set_reminder2 && !$set_reminder3) {
$dates->push($this->addTimeInterval($invoice->last_sent_date, (int)$settings->endless_reminder_frequency_id));
}
//order the dates ascending and get first one
return $dates->sort()->first();
}
/**
* Helper method which switches values based on the $schedule_reminder
* @param Invoice $invoice
* @param string $schedule_reminder
* @param int $num_days_reminder
* @return Carbon $date
*/
private function calculateScheduledDate($invoice, $schedule_reminder, $num_days_reminder) :?Carbon
{
switch ($schedule_reminder) {
case 'after_invoice_date':
return Carbon::parse($invoice->date)->addDays($num_days_reminder)->startOfDay();
break;
case 'before_due_date':
return Carbon::parse($invoice->due_date)->subDays($num_days_reminder)->startOfDay();
break;
case 'after_due_date':
return Carbon::parse($invoice->due_date)->addDays($num_days_reminder)->startOfDay();
break;
default:
return null;
break;
}
}
/**
* Sends the reminder and/or late fee for the invoice.
*
* @param Invoice $invoice
* @param string $template
* @return void
*/
private function sendReminder($invoice, $template) :void
{
$invoice = $this->calcLateFee($invoice, $template);
$invoice->invitations->each(function ($invitation) use($template, $invoice){
//only send if enable_reminder setting is toggled to yes
if($this->checkSendSetting($invoice, $template)) {
info("firing email");
EmailEntity::dispatchNow($invitation, $invitation->company, $template);
}
});
if($this->checkSendSetting($invoice, $template))
event(new InvoiceWasEmailed($invoice->invitations->first(), $invoice->company, Ninja::eventVars()));
$invoice->last_sent_date = now();
$invoice->next_send_date = $this->calculateNextSendDate($invoice);
if(in_array($template, ['reminder1', 'reminder2', 'reminder3']))
$invoice->{$template."_sent"} = now();
$invoice->save();
}
/**
* Calculates the late if - if any - and rebuilds the invoice
*
* @param Invoice $invoice
* @param string $template
* @return Invoice
*/
private function calcLateFee($invoice, $template) :Invoice
{
$late_fee_amount = 0;
$late_fee_percent = 0;
switch ($template) {
case 'reminder1':
$late_fee_amount = $invoice->client->getSetting('late_fee_amount1');
$late_fee_percent = $invoice->client->getSetting('late_fee_percent1');
break;
case 'reminder2':
$late_fee_amount = $invoice->client->getSetting('late_fee_amount2');
$late_fee_percent = $invoice->client->getSetting('late_fee_percent2');
break;
case 'reminder3':
$late_fee_amount = $invoice->client->getSetting('late_fee_amount3');
$late_fee_percent = $invoice->client->getSetting('late_fee_percent3');
break;
case 'endless_reminder':
$late_fee_amount = $invoice->client->getSetting('late_fee_endless_amount');
$late_fee_percent = $invoice->client->getSetting('late_fee_endless_percent');
break;
default:
$late_fee_amount = 0;
$late_fee_percent = 0;
break;
}
return $this->setLateFee($invoice, $late_fee_amount, $late_fee_percent);
}
/**
* Applies the late fee to the invoice line items
*
* @param Invoice $invoice
* @param float $amount The fee amount
* @param float $percent The fee percentage amount
*
* @return Invoice
*/
private function setLateFee($invoice, $amount, $percent) :Invoice
{
$temp_invoice_balance = $invoice->balance;
if ($amount <= 0 && $percent <= 0)
return $invoice;
$fee = $amount;
if ($invoice->partial > 0)
$fee += round($invoice->partial * $percent / 100, 2);
else
$fee += round($invoice->balance * $percent / 100, 2);
$invoice_item = new InvoiceItem;
$invoice_item->type_id = '5';
$invoice_item->product_key = trans('texts.fee');
$invoice_item->notes = ctrans('texts.late_fee_added', ['date' => $this->formatDate(now()->startOfDay(), $invoice->client->date_format())]);
$invoice_item->quantity = 1;
$invoice_item->cost = $fee;
$invoice_items = $invoice->line_items;
$invoice_items[] = $invoice_item;
$invoice->line_items = $invoice_items;
/**Refresh Invoice values*/
$invoice = $invoice->calc()->getInvoice();
$this->invoice->client->service()->updateBalance($this->invoice->balance - $temp_invoice_balance)->save();
$this->invoice->ledger()->updateInvoiceBalance($this->invoice->balance - $temp_invoice_balance);
return $invoice;
}
}

View File

@ -2,6 +2,7 @@
namespace App\Jobs\Payment;
use App\DataMapper\Analytics\EmailInvoiceFailure;
use App\Events\Invoice\InvoiceWasEmailed;
use App\Events\Invoice\InvoiceWasEmailedAndFailed;
use App\Events\Payment\PaymentWasEmailed;
@ -10,7 +11,9 @@ use App\Helpers\Email\BuildEmail;
use App\Jobs\Mail\BaseMailerJob;
use App\Jobs\Utils\SystemLogger;
use App\Libraries\MultiDB;
use App\Mail\Engine\PaymentEmailEngine;
use App\Mail\TemplateEmail;
use App\Models\ClientContact;
use App\Models\Company;
use App\Models\Payment;
use App\Models\SystemLog;
@ -21,6 +24,7 @@ use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
use Turbo124\Beacon\Facades\LightLogs;
class EmailPayment extends BaseMailerJob implements ShouldQueue
{
@ -33,6 +37,9 @@ class EmailPayment extends BaseMailerJob implements ShouldQueue
private $contact;
private $company;
public $settings;
/**
* Create a new job instance.
*
@ -41,12 +48,12 @@ class EmailPayment extends BaseMailerJob implements ShouldQueue
* @param $contact
* @param $company
*/
public function __construct(Payment $payment, $email_builder, $contact, company)
public function __construct(Payment $payment, Company $company, ClientContact $contact)
{
$this->payment = $payment;
$this->email_builder = $email_builder;
$this->contact = $contact;
$this->company = $company;
$this->settings = $payment->client->getMergedSettings();
}
/**
@ -62,14 +69,15 @@ class EmailPayment extends BaseMailerJob implements ShouldQueue
if ($this->contact->email) {
MultiDB::setDb($this->payment->company->db); //this may fail if we don't pass the serialized object with the company record
//todo fix!!
MultiDB::setDb($this->company->db);
//if we need to set an email driver do it now
$this->setMailDriver();
$email_builder = (new PaymentEmailEngine($this->payment, $this->contact))->build();
Mail::to($this->contact->email, $this->contact->present()->name())
->send(new TemplateEmail($this->email_builder, $this->contact->user, $this->contact->customer));
->send(new TemplateEmail($email_builder, $this->contact->user, $this->contact->client));
if (count(Mail::failures()) > 0) {
event(new PaymentWasEmailedAndFailed($this->payment, Mail::failures(), Ninja::eventVars()));
@ -77,21 +85,22 @@ class EmailPayment extends BaseMailerJob implements ShouldQueue
return $this->logMailError(Mail::failures());
}
//fire any events
event(new PaymentWasEmailed($this->payment, $this->payment->company, Ninja::eventVars()));
//sleep(5);
}
}
private function logMailError($errors)
public function failed($exception = null)
{
SystemLogger::dispatch(
$errors,
SystemLog::CATEGORY_MAIL,
SystemLog::EVENT_MAIL_SEND,
SystemLog::TYPE_FAILURE,
$this->payment->client
);
info('the job failed');
$job_failure = new EmailInvoiceFailure();
$job_failure->string_metric5 = 'payment';
$job_failure->string_metric6 = $exception->getMessage();
LightLogs::create($job_failure)
->batch();
}
}

View File

@ -18,7 +18,6 @@ use App\Models\Product;
use App\Repositories\InvoiceRepository;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Capsule\Eloquent;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
@ -27,11 +26,11 @@ class UpdateOrCreateProduct implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private $products;
public $products;
private $invoice;
public $invoice;
private $company;
public $company;
/**
* Create a new job instance.
@ -58,8 +57,15 @@ class UpdateOrCreateProduct implements ShouldQueue
public function handle()
{
MultiDB::setDB($this->company->db);
//only update / create products - not tasks or gateway fees
$updateable_products = collect($this->products)->filter(function ($item) {
foreach ($this->products as $item) {
return $item->type_id == 1;
});
foreach ($updateable_products as $item) {
if (empty($item->product_key)) {
continue;
}

View File

@ -14,7 +14,6 @@ namespace App\Jobs\RecurringInvoice;
use App\DataMapper\Analytics\SendRecurringFailure;
use App\Events\Invoice\InvoiceWasEmailed;
use App\Factory\RecurringInvoiceToInvoiceFactory;
use App\Helpers\Email\InvoiceEmail;
use App\Jobs\Entity\EmailEntity;
use App\Models\Invoice;
use App\Models\RecurringInvoice;
@ -74,8 +73,6 @@ class SendRecurring implements ShouldQueue
$invoice->invitations->each(function ($invitation) use ($invoice) {
$email_builder = (new InvoiceEmail())->build($invitation);
if($invitation->contact && strlen($invitation->contact->email) >=1){
EmailEntity::dispatch($invitation, $invoice->company);
info("Firing email for invoice {$invoice->number}");

View File

@ -74,6 +74,7 @@ use App\Repositories\VendorRepository;
use App\Utils\Traits\CleanLineItems;
use App\Utils\Traits\CompanyGatewayFeesAndLimitsSaver;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Uploadable;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
@ -91,7 +92,7 @@ class Import implements ShouldQueue
use CompanyGatewayFeesAndLimitsSaver;
use MakesHash;
use CleanLineItems;
use Uploadable;
/**
* @var array
*/
@ -260,6 +261,14 @@ class Import implements ShouldQueue
$company_repository = new CompanyRepository();
$company_repository->save($data, $this->company);
if(isset($data['settings']->company_logo) && strlen($data['settings']->company_logo) > 0) {
$tempImage = tempnam(sys_get_temp_dir(), basename($data['settings']->company_logo));
copy($data['settings']->company_logo, $tempImage);
$this->uploadLogo($tempImage, $this->company, $this->company);
}
Company::reguard();
/*Improve memory handling by setting everything to null when we have finished*/
@ -963,6 +972,7 @@ class Import implements ShouldQueue
$modified['company_id'] = $this->company->id;
$modified['client_id'] = $this->transformId('clients', $resource['client_id']);
$modified['user_id'] = $this->processUserId($resource);
$cgt = ClientGatewayToken::Create($modified);
@ -992,7 +1002,7 @@ class Import implements ShouldQueue
unset($modified['id']);
$modified['company_id'] = $this->company->id;
$modified['user_id'] = $this->transformId('users', $resource['user_id']);
$modified['user_id'] = $this->processUserId($resource);
$task_status = TaskStatus::Create($modified);
@ -1022,7 +1032,7 @@ class Import implements ShouldQueue
unset($modified['id']);
$modified['company_id'] = $this->company->id;
$modified['user_id'] = $this->transformId('users', $resource['user_id']);
$modified['user_id'] = $this->processUserId($resource);
$expense_category = ExpenseCategory::Create($modified);
@ -1051,7 +1061,7 @@ class Import implements ShouldQueue
unset($modified['id']);
$modified['company_id'] = $this->company->id;
$modified['user_id'] = $this->transformId('users', $resource['user_id']);
$modified['user_id'] = $this->processUserId($resource);
if(isset($modified['client_id']))
$modified['client_id'] = $this->transformId('clients', $resource['client_id']);
@ -1092,7 +1102,7 @@ class Import implements ShouldQueue
unset($modified['id']);
$modified['company_id'] = $this->company->id;
$modified['user_id'] = $this->transformId('users', $resource['user_id']);
$modified['user_id'] = $this->processUserId($resource);
if(isset($modified['client_id']))
$modified['client_id'] = $this->transformId('clients', $resource['client_id']);
@ -1125,7 +1135,7 @@ class Import implements ShouldQueue
unset($modified['id']);
$modified['company_id'] = $this->company->id;
$modified['user_id'] = $this->transformId('users', $resource['user_id']);
$modified['user_id'] = $this->processUserId($resource);
if(isset($resource['client_id']))
$modified['client_id'] = $this->transformId('clients', $resource['client_id']);

View File

@ -12,7 +12,6 @@
namespace App\Jobs\Util;
use App\Events\Invoice\InvoiceWasEmailed;
use App\Helpers\Email\InvoiceEmail;
use App\Jobs\Invoice\EmailInvoice;
use App\Libraries\MultiDB;
use App\Models\Account;
@ -69,11 +68,9 @@ class ReminderJob implements ShouldQueue
$reminder_template = $invoice->calculateTemplate('invoice');
$invoice->service()->touchReminder($this->reminder_template)->save();
$invoice->invitations->each(function ($invitation) use ($invoice) {
$email_builder = (new InvoiceEmail())->build($invitation);
EmailInvoice::dispatch($email_builder, $invitation, $invoice->company);
$invoice->invitations->each(function ($invitation) use ($invoice, $reminder_template) {
EmailEntity::dispatch($invitation, $invitation->company, $reminder_template);
info("Firing email for invoice {$invoice->number}");
});

View File

@ -11,9 +11,7 @@
namespace App\Jobs\Util;
use App\Helpers\Email\InvoiceEmail;
use App\Jobs\Entity\EmailEntity;
use App\Jobs\Invoice\EmailInvoice;
use App\Libraries\MultiDB;
use App\Models\SystemLog;
use Illuminate\Bus\Queueable;
@ -66,10 +64,9 @@ class SendFailedEmails implements ShouldQueue
$invitation = $job_meta_array['entity_name']::where('key', $job_meta_array['invitation_key'])->with('contact')->first();
if ($invitation->invoice) {
$email_builder = (new InvoiceEmail())->build($invitation, $job_meta_array['reminder_template']);
if ($invitation->contact->send_email && $invitation->contact->email) {
EmailEntity::dispatch($invitation, $invitation->company);
EmailEntity::dispatch($invitation, $invitation->company, $job_meta_array['reminder_template']);
}
}
});

View File

@ -1,5 +1,13 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Util;
use App\Models\Webhook;
@ -40,7 +48,7 @@ class WebhookHandler implements ShouldQueue
* @return bool
*/
public function handle() :bool
{
{//todo set multidb here
if (! $this->entity->company || $this->entity->company->is_disabled) {
return true;
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\Invoice;
use App\Models\Payment;
use App\Repositories\ActivityRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use stdClass;
class ClientUpdatedActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$client = $event->client;
$fields = new stdClass;
$fields->client_id = $client->id;
$fields->user_id = $client->user_id;
$fields->company_id = $client->company_id;
$fields->activity_type_id = Activity::UPDATE_CLIENT;
$this->activity_repo->save($fields, $client, $event->event_vars);
}
}

View File

@ -0,0 +1,54 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Repositories\ActivityRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use stdClass;
class CreatedExpenseActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$fields->expense_id = $event->expense->id;
$fields->user_id = $event->expense->user_id;
$fields->company_id = $event->expense->company_id;
$fields->activity_type_id = Activity::CREATE_EXPENSE;
$this->activity_repo->save($fields, $event->expense, $event->event_vars);
}
}

View File

@ -0,0 +1,54 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Repositories\ActivityRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use stdClass;
class CreatedTaskActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$fields->task_id = $event->task->id;
$fields->user_id = $event->task->user_id;
$fields->company_id = $event->task->company_id;
$fields->activity_type_id = Activity::CREATE_TASK;
$this->activity_repo->save($fields, $event->task, $event->event_vars);
}
}

View File

@ -0,0 +1,54 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Repositories\ActivityRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use stdClass;
class CreatedVendorActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$fields->vendor_id = $event->vendor->id;
$fields->user_id = $event->vendor->user_id;
$fields->company_id = $event->vendor->company_id;
$fields->activity_type_id = Activity::CREATE_VENDOR;
$this->activity_repo->save($fields, $event->vendor, $event->event_vars);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\Invoice;
use App\Models\Payment;
use App\Repositories\ActivityRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use stdClass;
class ExpenseArchivedActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$expense = $event->expense;
$fields = new stdClass;
$fields->expense_id = $expense->id;
$fields->user_id = $expense->user_id;
$fields->company_id = $expense->company_id;
$fields->activity_type_id = Activity::ARCHIVE_EXPENSE;
$this->activity_repo->save($fields, $expense, $event->event_vars);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\ClientContact;
use App\Models\InvoiceInvitation;
use App\Repositories\ActivityRepository;
use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
use stdClass;
class ExpenseDeletedActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$fields->expense_id = $event->expense->id;
$fields->user_id = $event->expense->user_id;
$fields->company_id = $event->expense->company_id;
$fields->activity_type_id = Activity::DELETE_VENDOR;
$this->activity_repo->save($fields, $event->expense, $event->event_vars);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\ClientContact;
use App\Models\InvoiceInvitation;
use App\Repositories\ActivityRepository;
use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
use stdClass;
class ExpenseRestoredActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$fields->expense_id = $event->expense->id;
$fields->user_id = $event->expense->user_id;
$fields->company_id = $event->expense->company_id;
$fields->activity_type_id = Activity::RESTORE_EXPENSE;
$this->activity_repo->save($fields, $event->expense, $event->event_vars);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\Invoice;
use App\Models\Payment;
use App\Repositories\ActivityRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use stdClass;
class ExpenseUpdatedActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$expense = $event->expense;
$fields = new stdClass;
$fields->expense_id = $expense->id;
$fields->user_id = $expense->user_id;
$fields->company_id = $expense->company_id;
$fields->activity_type_id = Activity::UPDATE_EXPENSE;
$this->activity_repo->save($fields, $expense, $event->event_vars);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\Invoice;
use App\Models\Payment;
use App\Repositories\ActivityRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use stdClass;
class TaskArchivedActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$task = $event->task;
$fields = new stdClass;
$fields->task_id = $task->id;
$fields->user_id = $task->user_id;
$fields->company_id = $task->company_id;
$fields->activity_type_id = Activity::ARCHIVE_TASK;
$this->activity_repo->save($fields, $task, $event->event_vars);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\ClientContact;
use App\Models\InvoiceInvitation;
use App\Repositories\ActivityRepository;
use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
use stdClass;
class TaskDeletedActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$fields->task_id = $event->task->id;
$fields->user_id = $event->task->user_id;
$fields->company_id = $event->task->company_id;
$fields->activity_type_id = Activity::DELETE_TASK;
$this->activity_repo->save($fields, $event->task, $event->event_vars);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\ClientContact;
use App\Models\InvoiceInvitation;
use App\Repositories\ActivityRepository;
use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
use stdClass;
class TaskRestoredActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$fields->task_id = $event->task->id;
$fields->user_id = $event->task->user_id;
$fields->company_id = $event->task->company_id;
$fields->activity_type_id = Activity::RESTORE_TASK;
$this->activity_repo->save($fields, $event->task, $event->event_vars);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\Invoice;
use App\Models\Payment;
use App\Repositories\ActivityRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use stdClass;
class TaskUpdatedActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$task = $event->task;
$fields = new stdClass;
$fields->task_id = $task->id;
$fields->user_id = $task->user_id;
$fields->company_id = $task->company_id;
$fields->activity_type_id = Activity::UPDATE_TASK;
$this->activity_repo->save($fields, $task, $event->event_vars);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\Invoice;
use App\Models\Payment;
use App\Repositories\ActivityRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use stdClass;
class VendorArchivedActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$vendor = $event->vendor;
$fields = new stdClass;
$fields->vendor_id = $vendor->id;
$fields->user_id = $vendor->user_id;
$fields->company_id = $vendor->company_id;
$fields->activity_type_id = Activity::ARCHIVE_VENDOR;
$this->activity_repo->save($fields, $vendor, $event->event_vars);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\ClientContact;
use App\Models\InvoiceInvitation;
use App\Repositories\ActivityRepository;
use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
use stdClass;
class VendorDeletedActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$fields->vendor_id = $event->vendor->id;
$fields->user_id = $event->vendor->user_id;
$fields->company_id = $event->vendor->company_id;
$fields->activity_type_id = Activity::DELETE_VENDOR;
$this->activity_repo->save($fields, $event->vendor, $event->event_vars);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\ClientContact;
use App\Models\InvoiceInvitation;
use App\Repositories\ActivityRepository;
use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
use stdClass;
class VendorRestoredActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$fields->vendor_id = $event->vendor->id;
$fields->user_id = $event->vendor->user_id;
$fields->company_id = $event->vendor->company_id;
$fields->activity_type_id = Activity::RESTORE_VENDOR;
$this->activity_repo->save($fields, $event->vendor, $event->event_vars);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Activity;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\Invoice;
use App\Models\Payment;
use App\Repositories\ActivityRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use stdClass;
class VendorUpdatedActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$vendor = $event->vendor;
$fields = new stdClass;
$fields->vendor_id = $vendor->id;
$fields->user_id = $vendor->user_id;
$fields->company_id = $vendor->company_id;
$fields->activity_type_id = Activity::UPDATE_VENDOR;
$this->activity_repo->save($fields, $vendor, $event->event_vars);
}
}

View File

@ -0,0 +1,59 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Invoice;
use App\Libraries\MultiDB;
use App\Models\Activity;
use App\Models\ClientContact;
use App\Models\InvoiceInvitation;
use App\Repositories\ActivityRepository;
use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
use stdClass;
class InvoiceReminderEmailActivity implements ShouldQueue
{
protected $activity_repo;
/**
* Create the event listener.
*
* @param ActivityRepository $activity_repo
*/
public function __construct(ActivityRepository $activity_repo)
{
$this->activity_repo = $activity_repo;
}
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
MultiDB::setDb($event->company->db);
$fields = new stdClass;
$fields->invoice_id = $event->invitation->invoice->id;
$fields->user_id = $event->invitation->invoice->user_id;
$fields->company_id = $event->invitation->invoice->company_id;
$fields->client_contact_id = $event->invitation->invoice->client_contact_id;
$fields->activity_type_id = $event->reminder;
$this->activity_repo->save($fields, $event->invitation->invoice, $event->event_vars);
}
}

View File

@ -63,7 +63,7 @@ class PaymentNotification implements ShouldQueue
if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]);
EntityPaidMailer::dispatch($payment, $payment->company);
EntityPaidMailer::dispatch($payment, $payment->company, $user);
}

View File

@ -54,6 +54,9 @@ class BaseEmailEngine implements EngineInterface
public function setSubject($subject)
{
if (! empty($this->variables))
$subject = str_replace(array_keys($this->variables), array_values($this->variables), $subject);
$this->subject = $subject;
return $this;
@ -61,6 +64,9 @@ class BaseEmailEngine implements EngineInterface
public function setBody($body)
{
if (! empty($this->variables))
$body = str_replace(array_keys($this->variables), array_values($this->variables), $body);
$this->body = $body;
return $this;

View File

@ -26,19 +26,25 @@ class CreditEmailEngine extends BaseEmailEngine
public $reminder_template;
public function __construct($invitation, $reminder_template)
public $template_data;
public function __construct($invitation, $reminder_template, $template_data)
{
$this->invitation = $invitation;
$this->reminder_template = $reminder_template;
$this->client = $invitation->contact->client;
$this->credit = $invitation->credit;
$this->contact = $invitation->contact;
$this->template_data = $template_data;
}
public function build()
{
$body_template = $this->client->getSetting('email_template_'.$this->reminder_template);
if(is_array($this->template_data) && array_key_exists('body', $this->template_data) && strlen($this->template_data['body']) > 0)
$body_template = $this->template_data['body'];
else
$body_template = $this->client->getSetting('email_template_'.$this->reminder_template);
/* Use default translations if a custom message has not been set*/
if (iconv_strlen($body_template) == 0) {
@ -54,7 +60,10 @@ class CreditEmailEngine extends BaseEmailEngine
);
}
$subject_template = $this->client->getSetting('email_subject_'.$this->reminder_template);
if(is_array($this->template_data) && array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0)
$subject_template = $this->template_data['subject'];
else
$subject_template = $this->client->getSetting('email_subject_'.$this->reminder_template);
if (iconv_strlen($subject_template) == 0) {

Some files were not shown because too many files have changed in this diff Show More