mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 05:02:36 +01:00
Implement EmailInvoice Job (#3166)
* Working on quote counter * Add tests for quote number + shared counter tests * Create invoice job * Add last_sent_date to invoice/quote table, remove type_id * Implement EmailInvoice Job
This commit is contained in:
parent
b0da84baa7
commit
5e7512071f
@ -11,6 +11,7 @@ use App\Factory\InvoiceItemFactory;
|
||||
use App\Factory\PaymentFactory;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use App\Jobs\Company\UpdateCompanyLedgerWithInvoice;
|
||||
use App\Jobs\Invoice\CreateInvoiceInvitations;
|
||||
use App\Jobs\Invoice\UpdateInvoicePayment;
|
||||
use App\Listeners\Invoice\CreateInvoiceInvitation;
|
||||
use App\Models\CompanyToken;
|
||||
@ -316,8 +317,8 @@ class CreateTestData extends Command
|
||||
|
||||
$this->invoice_repo->markSent($invoice);
|
||||
|
||||
event(new InvoiceWasMarkedSent($invoice));
|
||||
|
||||
CreateInvoiceInvitations::dispatch($invoice);
|
||||
|
||||
if(rand(0, 1)) {
|
||||
|
||||
$payment = PaymentFactory::create($client->company->id, $client->user->id);
|
||||
|
@ -2,7 +2,10 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Factory\ClientFactory;
|
||||
use App\Mail\TemplateEmail;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\User;
|
||||
use Illuminate\Console\Command;
|
||||
@ -43,7 +46,9 @@ class SendTestEmails extends Command
|
||||
public function handle()
|
||||
{
|
||||
$this->sendTemplateEmails('plain');
|
||||
sleep(5);
|
||||
$this->sendTemplateEmails('light');
|
||||
sleep(5);
|
||||
$this->sendTemplateEmails('dark');
|
||||
}
|
||||
|
||||
@ -57,21 +62,48 @@ class SendTestEmails extends Command
|
||||
];
|
||||
|
||||
$user = User::whereEmail('user@example.com')->first();
|
||||
$client = Client::all()->first();
|
||||
|
||||
if(!$user){
|
||||
$user = factory(\App\Models\User::class)->create([
|
||||
'confirmation_code' => '123',
|
||||
'email' => 'admin@business.com',
|
||||
'first_name' => 'John',
|
||||
'last_name' => 'Doe',
|
||||
]);
|
||||
}
|
||||
|
||||
if(!$client) {
|
||||
|
||||
$client = ClientFactory::create($user->company()->id, $user->id);
|
||||
$client->save();
|
||||
|
||||
factory(\App\Models\ClientContact::class,1)->create([
|
||||
'user_id' => $user->id,
|
||||
'client_id' => $client->id,
|
||||
'company_id' => $company->id,
|
||||
'is_primary' => 1,
|
||||
'send_invoice' => true,
|
||||
'email' => 'exy@example.com',
|
||||
]);
|
||||
|
||||
factory(\App\Models\ClientContact::class,1)->create([
|
||||
'user_id' => $user->id,
|
||||
'client_id' => $client->id,
|
||||
'company_id' => $company->id,
|
||||
'send_invoice' => true,
|
||||
'email' => 'exy2@example.com',
|
||||
]);
|
||||
}
|
||||
|
||||
$cc_emails = [config('ninja.testvars.test_email')];
|
||||
$bcc_emails = [config('ninja.testvars.test_email')];
|
||||
|
||||
Mail::to(config('ninja.testvars.test_email'))
|
||||
Mail::to(config('ninja.testvars.test_email'),'Mr Test')
|
||||
->cc($cc_emails)
|
||||
->bcc($bcc_emails)
|
||||
//->replyTo(also_available_if_needed)
|
||||
->send(new TemplateEmail($message, $template, $user));
|
||||
->send(new TemplateEmail($message, $template, $user, $client));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ class CompanySettings extends BaseSettings
|
||||
public $translations;
|
||||
|
||||
public $counter_number_applied = 'when_saved'; // when_saved , when_sent , when_paid
|
||||
public $quote_number_applied = 'when_saved'; // when_saved , when_sent
|
||||
/* Counters */
|
||||
public $invoice_number_pattern = '';
|
||||
public $invoice_number_counter = 1;
|
||||
@ -222,6 +223,7 @@ class CompanySettings extends BaseSettings
|
||||
'gmail_sending_user_id' => 'string',
|
||||
'currency_id' => 'string',
|
||||
'counter_number_applied' => 'string',
|
||||
'quote_number_applied' => 'string',
|
||||
'email_subject_custom1' => 'string',
|
||||
'email_subject_custom2' => 'string',
|
||||
'email_subject_custom3' => 'string',
|
||||
|
@ -26,19 +26,13 @@ class InvoiceWasEmailed
|
||||
*/
|
||||
public $invoice;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $notes;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param Invoice $invoice
|
||||
*/
|
||||
public function __construct(Invoice $invoice, $notes)
|
||||
public function __construct(Invoice $invoice)
|
||||
{
|
||||
$this->invoice = $invoice;
|
||||
$this->notes = $notes;
|
||||
}
|
||||
}
|
||||
|
45
app/Events/Invoice/InvoiceWasEmailedAndFailed.php
Normal file
45
app/Events/Invoice/InvoiceWasEmailedAndFailed.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Events\Invoice;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class InvoiceWasEmailedAndFailed.
|
||||
*/
|
||||
class InvoiceWasEmailedAndFailed
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* @var Invoice
|
||||
*/
|
||||
public $invoice;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $errors;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param Invoice $invoice
|
||||
*/
|
||||
public function __construct(Invoice $invoice, array $errors)
|
||||
{
|
||||
$this->invoice = $invoice;
|
||||
|
||||
$this->errors = $errors;
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ use App\Http\Requests\Invoice\ShowInvoiceRequest;
|
||||
use App\Http\Requests\Invoice\StoreInvoiceRequest;
|
||||
use App\Http\Requests\Invoice\UpdateInvoiceRequest;
|
||||
use App\Jobs\Entity\ActionEntity;
|
||||
use App\Jobs\Invoice\EmailInvoice;
|
||||
use App\Jobs\Invoice\MarkInvoicePaid;
|
||||
use App\Jobs\Invoice\StoreInvoice;
|
||||
use App\Models\Invoice;
|
||||
@ -660,7 +661,7 @@ class InvoiceController extends BaseController
|
||||
return $this->listResponse($invoice);
|
||||
break;
|
||||
case 'email':
|
||||
|
||||
EmailInvoice::dispatch($invoice);
|
||||
if(!$bulk)
|
||||
return response()->json(['message'=>'email sent'],200);
|
||||
break;
|
||||
|
@ -21,10 +21,11 @@
|
||||
* @OA\Property(property="email_style", type="string", example="light", description="options include plain,light,dark,custom"),
|
||||
* @OA\Property(property="reply_to_email", type="string", example="email@gmail.com", description="The reply to email address"),
|
||||
* @OA\Property(property="bcc_email", type="string", example="email@gmail.com, contact@gmail.com", description="A comma separate list of BCC emails"),
|
||||
*
|
||||
* @OA\Property(property="pdf_email_attachment", type="boolean", example=true, description="Toggles whether to attach PDF as attachment"),
|
||||
* @OA\Property(property="ubl_email_attachment", type="boolean", example=true, description="Toggles whether to attach UBL as attachment"),
|
||||
* @OA\Property(property="email_style_custom", type="string", example="<HTML></HTML>", description="The custom template"),
|
||||
* @OA\Property(property="counter_number_applied", type="string", example="when_sent", description="enum when the invoice number counter is set, ie when_saved, when_sent, when_paid"),
|
||||
* @OA\Property(property="quote_number_applied", type="string", example="when_sent", description="enum when the quote number counter is set, ie when_saved, when_sent"),
|
||||
* @OA\Property(property="custom_message_dashboard", type="string", example="Please pay invoices immediately", description="____________"),
|
||||
* @OA\Property(property="custom_message_unpaid_invoice", type="string", example="Please pay invoices immediately", description="____________"),
|
||||
* @OA\Property(property="custom_message_paid_invoice", type="string", example="Thanks for paying this invoice!", description="____________"),
|
||||
@ -44,7 +45,6 @@
|
||||
* @OA\Property(property="vendor_number_counter", type="integer", example="1", description="____________"),
|
||||
* @OA\Property(property="ticket_number_pattern", type="string", example="{$year}-{$counter}", description="Allows customisation of the ticket number pattern"),
|
||||
* @OA\Property(property="ticket_number_counter", type="integer", example="1", description="____________"),
|
||||
*
|
||||
* @OA\Property(property="payment_number_pattern", type="string", example="{$year}-{$counter}", description="Allows customisation of the payment number pattern"),
|
||||
* @OA\Property(property="payment_number_counter", type="integer", example="1", description="____________"),
|
||||
* @OA\Property(property="invoice_number_pattern", type="string", example="{$year}-{$counter}", description="Allows customisation of the invoice number pattern"),
|
||||
|
@ -5,10 +5,10 @@
|
||||
* type="object",
|
||||
* @OA\Property(property="id", type="string", example="Opnel5aKBz", description="_________"),
|
||||
* @OA\Property(property="user_id", type="string", example="", description="__________"),
|
||||
* @OA\Property(property="assigned_user_id", type="string", example="", description="__________"),
|
||||
* @OA\Property(property="company_id", type="string", example="", description="________"),
|
||||
* @OA\Property(property="client_id", type="string", example="", description="________"),
|
||||
* @OA\Property(property="status_id", type="string", example="", description="________"),
|
||||
* @OA\Property(property="invoice_type_id", type="string", example="", description="________"),
|
||||
* @OA\Property(property="number", type="string", example="INV_101", description="The invoice number - is a unique alpha numeric number per invoice per company"),
|
||||
* @OA\Property(property="po_number", type="string", example="", description="________"),
|
||||
* @OA\Property(property="terms", type="string", example="", description="________"),
|
||||
@ -35,6 +35,7 @@
|
||||
* @OA\Property(property="is_deleted", type="boolean", example=true, description="_________"),
|
||||
* @OA\Property(property="uses_inclusive_taxes", type="boolean", example=true, description="Defines the type of taxes used as either inclusive or exclusive"),
|
||||
* @OA\Property(property="date", type="string", format="date", example="1994-07-30", description="The Invoice Date"),
|
||||
* @OA\Property(property="last_sent_date", type="string", format="date", example="1994-07-30", description="The last date the invoice was sent out"),
|
||||
* @OA\Property(property="next_send_date", type="string", format="date", example="1994-07-30", description="The Next date for a reminder to be sent"),
|
||||
* @OA\Property(property="partial_due_date", type="string", format="date", example="1994-07-30", description="_________"),
|
||||
* @OA\Property(property="due_date", type="string", format="date", example="1994-07-30", description="_________"),
|
||||
|
@ -3,8 +3,50 @@
|
||||
* @OA\Schema(
|
||||
* schema="Quote",
|
||||
* type="object",
|
||||
* @OA\Property(property="id", type="string", example="Opnel5aKBz", description="______"),
|
||||
* @OA\Property(property="id", type="string", example="Opnel5aKBz", description="_________"),
|
||||
* @OA\Property(property="user_id", type="string", example="", description="__________"),
|
||||
* @OA\Property(property="assigned_user_id", type="string", example="", description="__________"),
|
||||
* @OA\Property(property="company_id", type="string", example="", description="________"),
|
||||
* @OA\Property(property="client_id", type="string", example="", description="________"),
|
||||
* @OA\Property(property="status_id", type="string", example="", description="________"),
|
||||
* @OA\Property(property="number", type="string", example="QUOTE_101", description="The quote number - is a unique alpha numeric number per quote per company"),
|
||||
* @OA\Property(property="po_number", type="string", example="", description="________"),
|
||||
* @OA\Property(property="terms", type="string", example="", description="________"),
|
||||
* @OA\Property(property="public_notes", type="string", example="", description="________"),
|
||||
* @OA\Property(property="private_notes", type="string", example="", description="________"),
|
||||
* @OA\Property(property="footer", type="string", example="", description="________"),
|
||||
* @OA\Property(property="custom_value1", type="string", example="", description="________"),
|
||||
* @OA\Property(property="custom_value2", type="string", example="", description="________"),
|
||||
* @OA\Property(property="custom_value3", type="string", example="", description="________"),
|
||||
* @OA\Property(property="custom_value4", type="string", example="", description="________"),
|
||||
* @OA\Property(property="tax_name1", type="string", example="", description="________"),
|
||||
* @OA\Property(property="tax_name2", type="string", example="", description="________"),
|
||||
* @OA\Property(property="tax_rate1", type="number", format="float", example="10.00", description="_________"),
|
||||
* @OA\Property(property="tax_rate2", type="number", format="float", example="10.00", description="_________"),
|
||||
* @OA\Property(property="tax_name3", type="string", example="", description="________"),
|
||||
* @OA\Property(property="tax_rate3", type="number", format="float", example="10.00", description="_________"),
|
||||
* @OA\Property(property="total_taxes", type="number", format="float", example="10.00", description="The total taxes for the quote"),
|
||||
* @OA\Property(property="line_items", type="object", example="", description="_________"),
|
||||
* @OA\Property(property="amount", type="number", format="float", example="10.00", description="_________"),
|
||||
* @OA\Property(property="balance", type="number", format="float", example="10.00", description="_________"),
|
||||
* @OA\Property(property="discount", type="number", format="float", example="10.00", description="_________"),
|
||||
* @OA\Property(property="partial", type="number", format="float", example="10.00", description="_________"),
|
||||
* @OA\Property(property="is_amount_discount", type="boolean", example=true, description="_________"),
|
||||
* @OA\Property(property="is_deleted", type="boolean", example=true, description="_________"),
|
||||
* @OA\Property(property="uses_inclusive_taxes", type="boolean", example=true, description="Defines the type of taxes used as either inclusive or exclusive"),
|
||||
* @OA\Property(property="date", type="string", format="date", example="1994-07-30", description="The Quote Date"),
|
||||
* @OA\Property(property="last_sent_date", type="string", format="date", example="1994-07-30", description="The last date the quote was sent out"),
|
||||
* @OA\Property(property="next_send_date", type="string", format="date", example="1994-07-30", description="The Next date for a reminder to be sent"),
|
||||
* @OA\Property(property="partial_due_date", type="string", format="date", example="1994-07-30", description="_________"),
|
||||
* @OA\Property(property="due_date", type="string", format="date", example="1994-07-30", description="_________"),
|
||||
* @OA\Property(property="settings",ref="#/components/schemas/CompanySettings"),
|
||||
* @OA\Property(property="last_viewed", type="number", format="integer", example="1434342123", description="Timestamp"),
|
||||
* @OA\Property(property="updated_at", type="number", format="integer", example="1434342123", description="Timestamp"),
|
||||
* @OA\Property(property="archived_at", type="number", format="integer", example="1434342123", description="Timestamp"),
|
||||
* @OA\Property(property="custom_surcharge1", type="number", format="float", example="10.00", description="First Custom Surcharge"),
|
||||
* @OA\Property(property="custom_surcharge2", type="number", format="float", example="10.00", description="Second Custom Surcharge"),
|
||||
* @OA\Property(property="custom_surcharge3", type="number", format="float", example="10.00", description="Third Custom Surcharge"),
|
||||
* @OA\Property(property="custom_surcharge4", type="number", format="float", example="10.00", description="Fourth Custom Surcharge"),
|
||||
* @OA\Property(property="custom_surcharge_taxes", type="boolean", example=true, description="Toggles charging taxes on custom surcharge amounts"),
|
||||
* )
|
||||
*/
|
111
app/Jobs/Invoice/EmailInvoice.php
Normal file
111
app/Jobs/Invoice/EmailInvoice.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Jobs\Invoice;
|
||||
|
||||
use App\Events\Invoice\InvoiceWasEmailed;
|
||||
use App\Events\Invoice\InvoiceWasEmailedAndFailed;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Mail\TemplateEmail;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\SystemLog;
|
||||
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\Mail;
|
||||
|
||||
class EmailInvoice implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public $invoice;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Invoice $invoice)
|
||||
{
|
||||
|
||||
$this->invoice = $invoice;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
/*Jobs are not multi-db aware, need to set! */
|
||||
MultiDB::setDB($this->invoice->company->db);
|
||||
|
||||
$message_array = $this->invoice->getEmailData();
|
||||
$message_array['title'] = &$message_array['subject'];
|
||||
$message_array['footer'] = 'The Footer';
|
||||
//
|
||||
|
||||
$variables = array_merge($this->invoice->makeLabels(), $this->invoice->makeValues());
|
||||
|
||||
$template_style = $this->invoice->client->getSetting('email_style');
|
||||
|
||||
$this->invoice->invitations->each(function ($invitation) use($message_array, $template_style, $variables){
|
||||
|
||||
if($invitation->contact->send_invoice && $invitation->contact->email)
|
||||
{
|
||||
//there may be template variables left over for the specific contact? need to reparse here //todo this wont work, as if the variables existed, they'll be overwritten already!
|
||||
$message_array['body'] = str_replace(array_keys($variables), array_values($variables), $message_array['body']);
|
||||
$message_array['subject'] = str_replace(array_keys($variables), array_values($variables), $message_array['subject']);
|
||||
|
||||
//change the runtime config of the mail provider here:
|
||||
|
||||
//send message
|
||||
Mail::to($invitation->contact->email)
|
||||
->send(new TemplateEmail($message_array, $template_style, $invitation->contact->user, $invitation->contact->client));
|
||||
|
||||
if( count(Mail::failures()) > 0 ) {
|
||||
|
||||
event(new InvoiceWasEmailedAndFailed($this->invoice, Mail::failures()));
|
||||
|
||||
return $this->logMailError($errors);
|
||||
|
||||
}
|
||||
|
||||
//fire any events
|
||||
event(new InvoiceWasEmailed($this->invoice));
|
||||
|
||||
sleep(5);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private function logMailError($errors)
|
||||
{
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$errors,
|
||||
SystemLog::CATEGORY_MAIL,
|
||||
SystemLog::EVENT_MAIL_SEND,
|
||||
SystemLog::TYPE_FAILURE,
|
||||
$this->invoice->client
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -137,7 +137,8 @@ class UpdateInvoicePayment implements ShouldQueue
|
||||
'invoices' => $invoices,
|
||||
'invoices_total' => $invoices_total,
|
||||
'payment_amount' => $this->payment->amount,
|
||||
'partial_check_amount' => $total, ],
|
||||
'partial_check_amount' => $total,
|
||||
],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_PAYMENT_RECONCILIATION_FAILURE,
|
||||
SystemLog::TYPE_LEDGER,
|
||||
|
81
app/Jobs/Quote/ApplyQuoteNumber.php
Normal file
81
app/Jobs/Quote/ApplyQuoteNumber.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* Quote Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2019. Quote Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Jobs\Quote;
|
||||
|
||||
use App\Models\Quote;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentTerm;
|
||||
use App\Repositories\QuoteRepository;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Utils\Traits\NumberFormatter;
|
||||
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 ApplyQuoteNumber implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, NumberFormatter, GeneratesCounter;
|
||||
|
||||
private $quote;
|
||||
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Quote $quote, $settings)
|
||||
{
|
||||
|
||||
$this->quote = $quote;
|
||||
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
//return early
|
||||
if($this->quote->number != '')
|
||||
return $this->quote;
|
||||
|
||||
switch ($this->settings->quote_number_applied) {
|
||||
case 'when_saved':
|
||||
$this->quote->number = $this->getNextQuoteNumber($this->quote->client);
|
||||
break;
|
||||
case 'when_sent':
|
||||
if($this->quote->status_id == Quote::STATUS_SENT)
|
||||
$this->quote->number = $this->getNextQuoteNumber($this->quote->client);
|
||||
break;
|
||||
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
|
||||
$this->quote->save();
|
||||
|
||||
return $this->quote;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
54
app/Listeners/Invoice/InvoiceEmailActivity.php
Normal file
54
app/Listeners/Invoice/InvoiceEmailActivity.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Listeners\Invoice;
|
||||
|
||||
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;
|
||||
|
||||
class InvoiceEmailActivity implements ShouldQueue
|
||||
{
|
||||
protected $activity_repo;
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ActivityRepository $activity_repo)
|
||||
{
|
||||
$this->activity_repo = $activity_repo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param object $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle($event)
|
||||
{
|
||||
|
||||
$fields = new \stdClass;
|
||||
|
||||
$fields->invoice_id = $event->invoice->id;
|
||||
$fields->user_id = $event->invoice->user_id;
|
||||
$fields->company_id = $event->invoice->company_id;
|
||||
$fields->activity_type_id = Activity::EMAIL_INVOICE;
|
||||
|
||||
$this->activity_repo->save($fields, $event->invoice);
|
||||
}
|
||||
}
|
54
app/Listeners/Invoice/InvoiceEmailFailedActivity.php
Normal file
54
app/Listeners/Invoice/InvoiceEmailFailedActivity.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2019. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Listeners\Invoice;
|
||||
|
||||
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;
|
||||
|
||||
class InvoiceEmailFailedActivity implements ShouldQueue
|
||||
{
|
||||
protected $activity_repo;
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ActivityRepository $activity_repo)
|
||||
{
|
||||
$this->activity_repo = $activity_repo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param object $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle($event)
|
||||
{
|
||||
|
||||
$fields = new \stdClass;
|
||||
|
||||
$fields->invoice_id = $event->invoice->id;
|
||||
$fields->user_id = $event->invoice->user_id;
|
||||
$fields->company_id = $event->invoice->company_id;
|
||||
$fields->activity_type_id = Activity::EMAIL_INVOICE_FAILED;
|
||||
|
||||
$this->activity_repo->save($fields, $event->invoice);
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ class TemplateEmail extends Mailable
|
||||
|
||||
private $template; //the template to use
|
||||
|
||||
private $message; //the message array (subject and body)
|
||||
private $message; //the message array // ['body', 'footer', 'title', 'files']
|
||||
|
||||
private $user; //the user the email will be sent from
|
||||
|
||||
@ -45,7 +45,7 @@ class TemplateEmail extends Mailable
|
||||
|
||||
$company = $this->client->company;
|
||||
|
||||
return $this->from($this->user->email, $this->user->present()->name()) //todo this needs to be fixed to handle the hosted version
|
||||
$message = $this->from($this->user->email, $this->user->present()->name()) //todo this needs to be fixed to handle the hosted version
|
||||
->subject($this->message['subject'])
|
||||
->text('email.template.plain', ['body' => $this->message['body'], 'footer' => $this->message['footer']])
|
||||
->view($template_name, [
|
||||
@ -56,5 +56,14 @@ class TemplateEmail extends Mailable
|
||||
'company' => $company
|
||||
]);
|
||||
|
||||
|
||||
//conditionally attach files
|
||||
if($settings->pdf_email_attachment !== false && array_key_exists($this->message['files'])){
|
||||
|
||||
foreach($this->message['files'] as $file)
|
||||
$message->attach($file);
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
}
|
@ -69,6 +69,7 @@ class Activity extends StaticModel
|
||||
const RESTORE_USER=52;
|
||||
const MARK_SENT_INVOICE=53;
|
||||
const PAID_INVOICE=54;
|
||||
const EMAIL_INVOICE_FAILED=57;
|
||||
|
||||
protected $casts = [
|
||||
'is_system' => 'boolean',
|
||||
|
@ -254,7 +254,7 @@ class Client extends BaseModel
|
||||
if($this->group_settings && (property_exists($this->group_settings->settings, $setting) !== false) && (isset($this->group_settings->settings->{$setting}) !== false)){
|
||||
return $this->group_settings->settings->{$setting};
|
||||
}
|
||||
|
||||
|
||||
/*Company Settings*/
|
||||
if((property_exists($this->company->settings, $setting) != false ) && (isset($this->company->settings->{$setting}) !== false) ){
|
||||
return $this->company->settings->{$setting};
|
||||
|
@ -17,6 +17,7 @@ class SystemLog extends Model
|
||||
{
|
||||
/* Category IDs */
|
||||
const CATEGORY_GATEWAY_RESPONSE = 1;
|
||||
const CATEGORY_MAIL = 2;
|
||||
|
||||
/* Event IDs*/
|
||||
const EVENT_PAYMENT_RECONCILIATION_FAILURE = 10;
|
||||
@ -26,10 +27,13 @@ class SystemLog extends Model
|
||||
const EVENT_GATEWAY_FAILURE = 22;
|
||||
const EVENT_GATEWAY_ERROR = 23;
|
||||
|
||||
const EVENT_MAIL_SEND = 30;
|
||||
|
||||
/*Type IDs*/
|
||||
const TYPE_PAYPAL = 300;
|
||||
const TYPE_STRIPE = 301;
|
||||
const TYPE_LEDGER = 302;
|
||||
const TYPE_FAILURE = 303;
|
||||
|
||||
protected $fillable = [
|
||||
'client_id',
|
||||
|
@ -199,6 +199,11 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||
|
||||
}
|
||||
|
||||
public function clients()
|
||||
{
|
||||
return $this->hasMany(Client::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a comma separated list of user permissions
|
||||
*
|
||||
|
@ -14,6 +14,7 @@ namespace App\Providers;
|
||||
use App\Events\Client\ClientWasCreated;
|
||||
use App\Events\Contact\ContactLoggedIn;
|
||||
use App\Events\Invoice\InvoiceWasCreated;
|
||||
use App\Events\Invoice\InvoiceWasEmailed;
|
||||
use App\Events\Invoice\InvoiceWasMarkedSent;
|
||||
use App\Events\Invoice\InvoiceWasPaid;
|
||||
use App\Events\Invoice\InvoiceWasUpdated;
|
||||
@ -29,6 +30,8 @@ use App\Listeners\Invoice\CreateInvoiceActivity;
|
||||
use App\Listeners\Invoice\CreateInvoiceHtmlBackup;
|
||||
use App\Listeners\Invoice\CreateInvoiceInvitation;
|
||||
use App\Listeners\Invoice\CreateInvoicePdf;
|
||||
use App\Listeners\Invoice\InvoiceEmailActivity;
|
||||
use App\Listeners\Invoice\InvoiceEmailFailedActivity;
|
||||
use App\Listeners\Invoice\UpdateInvoiceActivity;
|
||||
use App\Listeners\Invoice\UpdateInvoiceInvitations;
|
||||
use App\Listeners\Invoice\UpdateInvoicePayment;
|
||||
@ -96,7 +99,14 @@ class EventServiceProvider extends ServiceProvider
|
||||
],
|
||||
InvoiceWasPaid::class => [
|
||||
CreateInvoiceHtmlBackup::class,
|
||||
]
|
||||
],
|
||||
InvoiceWasEmailed::class => [
|
||||
InvoiceEmailActivity::class,
|
||||
],
|
||||
InvoiceWasEmailedAndFailed::class => [
|
||||
InvoiceEmailFailedActivity::class,
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -13,6 +13,7 @@ namespace App\Repositories;
|
||||
|
||||
use App\Factory\QuoteInvitationFactory;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use App\Jobs\Quote\ApplyQuoteNumber;
|
||||
use App\Jobs\Quote\CreateQuoteInvitations;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
@ -99,8 +100,8 @@ class QuoteRepository extends BaseRepository
|
||||
$quote->save();
|
||||
|
||||
$finished_amount = $quote->amount;
|
||||
//todo need answers on this
|
||||
// $quote = ApplyInvoiceNumber::dispatchNow($quote, $quote->client->getMergedSettings());
|
||||
|
||||
$quote = ApplyQuoteNumber::dispatchNow($quote, $quote->client->getMergedSettings());
|
||||
|
||||
return $quote->fresh();
|
||||
}
|
||||
|
@ -96,6 +96,7 @@ class InvoiceTransformer extends EntityTransformer
|
||||
'discount' => (float) $invoice->discount,
|
||||
'po_number' => $invoice->po_number ?: '',
|
||||
'date' => $invoice->date ?: '',
|
||||
'last_sent_date' => $invoice->last_sent_date ?: '',
|
||||
'next_send_date' => $invoice->date ?: '',
|
||||
'due_date' => $invoice->due_date ?: '',
|
||||
'terms' => $invoice->terms ?: '',
|
||||
@ -103,7 +104,6 @@ class InvoiceTransformer extends EntityTransformer
|
||||
'private_notes' => $invoice->private_notes ?: '',
|
||||
'is_deleted' => (bool) $invoice->is_deleted,
|
||||
'uses_inclusive_taxes' => (bool) $invoice->uses_inclusive_taxes,
|
||||
'invoice_type_id' => (string) $invoice->invoice_type_id ?: '',
|
||||
'tax_name1' => $invoice->tax_name1 ? $invoice->tax_name1 : '',
|
||||
'tax_rate1' => (float) $invoice->tax_rate1,
|
||||
'tax_name2' => $invoice->tax_name2 ? $invoice->tax_name2 : '',
|
||||
|
@ -85,6 +85,7 @@ class QuoteTransformer extends EntityTransformer
|
||||
'discount' => (float) $quote->discount,
|
||||
'po_number' => $quote->po_number ?: '',
|
||||
'date' => $quote->date ?: '',
|
||||
'last_sent_date' => $quote->last_sent_date ?: '',
|
||||
'next_send_date' => $quote->date ?: '',
|
||||
'due_date' => $quote->due_date ?: '',
|
||||
'terms' => $quote->terms ?: '',
|
||||
@ -92,7 +93,6 @@ class QuoteTransformer extends EntityTransformer
|
||||
'private_notes' => $quote->private_notes ?: '',
|
||||
'is_deleted' => (bool) $quote->is_deleted,
|
||||
'uses_inclusive_taxes' => (bool) $quote->uses_inclusive_taxes,
|
||||
'invoice_type_id' => (string) $quote->invoice_type_id ?: '',
|
||||
'tax_name1' => $quote->tax_name1 ? $quote->tax_name1 : '',
|
||||
'tax_rate1' => (float) $quote->tax_rate1,
|
||||
'tax_name2' => $quote->tax_name2 ? $quote->tax_name2 : '',
|
||||
|
@ -96,9 +96,44 @@ trait GeneratesCounter
|
||||
return $credit_number;
|
||||
}
|
||||
|
||||
public function getNextQuoteNumber()
|
||||
public function getNextQuoteNumber(Client $client)
|
||||
{
|
||||
//Reset counters if enabled
|
||||
$this->resetCounters($client);
|
||||
|
||||
$used_counter = 'quote_number_counter';
|
||||
|
||||
if($this->hasSharedCounter($client))
|
||||
$used_counter = 'invoice_number_counter';
|
||||
|
||||
//todo handle if we have specific client patterns in the future
|
||||
$pattern = $client->getSetting('quote_number_pattern');
|
||||
//Determine if we are using client_counters
|
||||
if(strpos($pattern, 'clientCounter'))
|
||||
{
|
||||
$counter = $client->settings->{$used_counter};
|
||||
$counter_entity = $client;
|
||||
}
|
||||
elseif(strpos($pattern, 'groupCounter'))
|
||||
{
|
||||
$counter = $client->group_settings->{$used_counter};
|
||||
$counter_entity = $client->group_settings;
|
||||
}
|
||||
else
|
||||
{
|
||||
$counter = $client->company->settings->{$used_counter};
|
||||
$counter_entity = $client->company;
|
||||
}
|
||||
|
||||
//Return a valid counter
|
||||
$pattern = $client->getSetting('quote_number_pattern');
|
||||
$padding = $client->getSetting('counter_padding');
|
||||
|
||||
$quote_number = $this->checkEntityNumber(Quote::class, $client, $counter, $padding, $pattern);
|
||||
|
||||
$this->incrementCounter($counter_entity, $used_counter);
|
||||
|
||||
return $quote_number;
|
||||
}
|
||||
|
||||
public function getNextRecurringInvoiceNumber()
|
||||
@ -170,9 +205,10 @@ trait GeneratesCounter
|
||||
* @return boolean True if has shared counter, False otherwise.
|
||||
*/
|
||||
public function hasSharedCounter(Client $client) : bool
|
||||
{
|
||||
|
||||
return $client->getSetting('shared_invoice_quote_counter') === TRUE;
|
||||
{
|
||||
// \Log::error((bool) $client->getSetting('shared_invoice_quote_counter'));
|
||||
// \Log::error($client->getSetting('shared_invoice_quote_counter'));
|
||||
return (bool) $client->getSetting('shared_invoice_quote_counter');
|
||||
|
||||
}
|
||||
|
||||
|
@ -65,10 +65,12 @@ trait InvoiceEmailBuilder
|
||||
|
||||
}
|
||||
|
||||
|
||||
$data['body'] = $this->parseTemplate($body_template, false);
|
||||
$data['subject'] = $this->parseTemplate($subject_template, true);
|
||||
|
||||
if($client->getSetting('pdf_email_attachment') !== false)
|
||||
$data['files'][] = $this->pdf_file_path();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@ -108,8 +110,11 @@ trait InvoiceEmailBuilder
|
||||
{
|
||||
return 'template3';
|
||||
}
|
||||
else
|
||||
return 'invoice';
|
||||
|
||||
//also implement endless reminders here
|
||||
//
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ return [
|
||||
'stripe' => env('STRIPE_KEYS',''),
|
||||
'paypal' => env('PAYPAL_KEYS', ''),
|
||||
'travis' => env('TRAVIS', false),
|
||||
'test_email' => env('TEST_EMAIL',''),
|
||||
'test_email' => env('TEST_EMAIL','test@example.com'),
|
||||
],
|
||||
'contact' => [
|
||||
'email' => env('MAIL_FROM_ADDRESS'),
|
||||
|
@ -452,6 +452,8 @@ class CreateUsersTable extends Migration
|
||||
|
||||
$t->string('po_number')->nullable();
|
||||
$t->date('date')->nullable();
|
||||
$t->date('last_sent_date')->nullable();
|
||||
|
||||
$t->datetime('due_date')->nullable();
|
||||
|
||||
$t->boolean('is_deleted')->default(false);
|
||||
@ -660,6 +662,8 @@ class CreateUsersTable extends Migration
|
||||
|
||||
$t->string('po_number')->nullable();
|
||||
$t->date('date')->nullable();
|
||||
$t->date('last_sent_date')->nullable();
|
||||
|
||||
$t->datetime('due_date')->nullable();
|
||||
$t->datetime('next_send_date')->nullable();
|
||||
|
||||
|
@ -801,6 +801,7 @@ $LANG = array(
|
||||
'activity_54' => ':user reopened ticket :ticket',
|
||||
'activity_55' => ':contact replied ticket :ticket',
|
||||
'activity_56' => ':user viewed ticket :ticket',
|
||||
'activity_57' => ':invoice failed to send to :client',
|
||||
|
||||
'payment' => 'Payment',
|
||||
'system' => 'System',
|
||||
|
@ -55,6 +55,7 @@ class InvoiceEmailTest extends TestCase
|
||||
$message_array['title'] = &$message_array['subject'];
|
||||
$message_array['footer'] = 'The Footer';
|
||||
|
||||
|
||||
// $template_style = $this->client->getSetting('email_style');
|
||||
|
||||
$template_style = 'light';
|
||||
@ -62,24 +63,24 @@ class InvoiceEmailTest extends TestCase
|
||||
|
||||
$invitations = InvoiceInvitation::whereInvoiceId($this->invoice->id)->get();
|
||||
|
||||
$invitations->each(function($invitation) use($message_array, $template_style) {
|
||||
$invitations->each(function($invitation) use($message_array, $template_styles) {
|
||||
|
||||
$contact = ClientContact::find($invitation->client_contact_id)->first();
|
||||
$contact = $invitation->contact;
|
||||
|
||||
if($contact->send_invoice && $contact->email)
|
||||
{
|
||||
//there may be template variables left over for the specific contact? need to reparse here
|
||||
|
||||
|
||||
//change the runtime config of the mail provider here:
|
||||
|
||||
//send message
|
||||
Mail::to($contact->email)
|
||||
->send(new TemplateEmail($message_array, $template_style, $this->user, $this->client));
|
||||
->send(new TemplateEmail($message_array, $template_style, $this->user, $contact->client));
|
||||
|
||||
//fire any events
|
||||
|
||||
|
||||
sleep(5);
|
||||
sleep(5);//here to cope with mailtrap time delays
|
||||
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,27 @@ class GeneratesCounterTest extends TestCase
|
||||
$this->assertFalse($this->hasSharedCounter($this->client));
|
||||
}
|
||||
|
||||
public function testHasTrueSharedCounter()
|
||||
{
|
||||
$settings = $this->client->getMergedSettings();
|
||||
$settings->invoice_number_counter = 1;
|
||||
$settings->invoice_number_pattern = '{$year}-{$counter}';
|
||||
$settings->shared_invoice_quote_counter = 1;
|
||||
$this->company->settings = $settings;
|
||||
|
||||
$this->company->save();
|
||||
|
||||
$this->client->settings = $settings;
|
||||
$this->client->save();
|
||||
|
||||
$gs = $this->client->group_settings;
|
||||
$gs->settings = $settings;
|
||||
$gs->save();
|
||||
|
||||
$this->assertTrue($this->hasSharedCounter($this->client));
|
||||
|
||||
}
|
||||
|
||||
public function testInvoiceNumberValue()
|
||||
{
|
||||
|
||||
@ -63,6 +84,19 @@ class GeneratesCounterTest extends TestCase
|
||||
|
||||
}
|
||||
|
||||
public function testQuoteNumberValue()
|
||||
{
|
||||
|
||||
$quote_number = $this->getNextQuoteNumber($this->client);
|
||||
|
||||
$this->assertEquals($quote_number, 0001);
|
||||
|
||||
$quote_number = $this->getNextQuoteNumber($this->client);
|
||||
|
||||
$this->assertEquals($quote_number, '0002');
|
||||
|
||||
}
|
||||
|
||||
public function testInvoiceNumberPattern()
|
||||
{
|
||||
$settings = $this->client->company->settings;
|
||||
@ -79,12 +113,58 @@ class GeneratesCounterTest extends TestCase
|
||||
$invoice_number = $this->getNextInvoiceNumber($this->client);
|
||||
$invoice_number2 = $this->getNextInvoiceNumber($this->client);
|
||||
|
||||
$this->assertEquals($invoice_number, '2019-0001');
|
||||
$this->assertEquals($invoice_number2, '2019-0002');
|
||||
$this->assertEquals($invoice_number, date('Y').'-0001');
|
||||
$this->assertEquals($invoice_number2, date('Y').'-0002');
|
||||
$this->assertEquals($this->client->company->settings->invoice_number_counter,3);
|
||||
|
||||
}
|
||||
|
||||
public function testQuoteNumberPattern()
|
||||
{
|
||||
$settings = $this->client->company->settings;
|
||||
$settings->quote_number_counter = 1;
|
||||
$settings->quote_number_pattern = '{$year}-{$counter}';
|
||||
|
||||
$this->client->company->settings = $settings;
|
||||
$this->client->company->save();
|
||||
|
||||
$this->client->settings = $settings;
|
||||
$this->client->save();
|
||||
$this->client->fresh();
|
||||
|
||||
$quote_number = $this->getNextQuoteNumber($this->client);
|
||||
$quote_number2 = $this->getNextQuoteNumber($this->client);
|
||||
|
||||
$this->assertEquals($quote_number, date('Y').'-0001');
|
||||
$this->assertEquals($quote_number2, date('Y').'-0002');
|
||||
$this->assertEquals($this->client->company->settings->quote_number_counter,3);
|
||||
|
||||
}
|
||||
|
||||
public function testQuoteNumberPatternWithSharedCounter()
|
||||
{
|
||||
$settings = $this->client->company->settings;
|
||||
$settings->quote_number_counter = 100;
|
||||
$settings->invoice_number_counter = 1000;
|
||||
$settings->quote_number_pattern = '{$year}-{$counter}';
|
||||
$settings->shared_invoice_quote_counter = true;
|
||||
|
||||
$this->client->company->settings = $settings;
|
||||
$this->client->company->save();
|
||||
|
||||
$gs = $this->client->group_settings;
|
||||
$gs->settings = $settings;
|
||||
$gs->save();
|
||||
|
||||
$quote_number = $this->getNextQuoteNumber($this->client);
|
||||
$quote_number2 = $this->getNextQuoteNumber($this->client);
|
||||
|
||||
$this->assertEquals($quote_number, date('Y').'-1000');
|
||||
$this->assertEquals($quote_number2, date('Y').'-1001');
|
||||
$this->assertEquals($this->client->company->settings->quote_number_counter,100);
|
||||
|
||||
}
|
||||
|
||||
public function testInvoiceClientNumberPattern()
|
||||
{
|
||||
$settings = $this->company->settings;
|
||||
@ -106,10 +186,10 @@ class GeneratesCounterTest extends TestCase
|
||||
|
||||
$invoice_number = $this->getNextClientNumber($this->client);
|
||||
|
||||
$this->assertEquals($invoice_number, '2019-0001');
|
||||
$this->assertEquals($invoice_number, date('Y').'-0001');
|
||||
|
||||
$invoice_number = $this->getNextClientNumber($this->client);
|
||||
$this->assertEquals($invoice_number, '2019-0002');
|
||||
$this->assertEquals($invoice_number, date('Y').'-0002');
|
||||
|
||||
|
||||
}
|
||||
@ -266,8 +346,8 @@ class GeneratesCounterTest extends TestCase
|
||||
$this->client->setSettingsByEntity(Client::class, $settings);
|
||||
$company = Company::find($this->client->company_id);
|
||||
$this->assertEquals($company->settings->client_number_counter,1);
|
||||
$this->assertEquals($this->getNextNumber($this->client), '2019-1');
|
||||
$this->assertEquals($this->getNextNumber($this->client), '2019-2');
|
||||
$this->assertEquals($this->getNextNumber($this->client), date('y').'-1');
|
||||
$this->assertEquals($this->getNextNumber($this->client), date('y').'-2');
|
||||
|
||||
$company = Company::find($this->client->company_id);
|
||||
$this->assertEquals($company->settings->client_number_counter,2);
|
||||
|
Loading…
Reference in New Issue
Block a user