mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge pull request #6865 from turbo124/v5-develop
Fixes for converting quotes to invoices - invitations
This commit is contained in:
commit
0c23c058c5
@ -781,7 +781,9 @@ class BaseController extends Controller
|
||||
case 'next':
|
||||
return 'main.next.dart.js';
|
||||
case 'profile':
|
||||
return 'main.profile.dart.js';
|
||||
return 'main.profile.dart.js';
|
||||
case 'html':
|
||||
return 'main.html.dart.js';
|
||||
default:
|
||||
return 'main.foss.dart.js';
|
||||
|
||||
|
@ -13,12 +13,14 @@ namespace App\Jobs\RecurringInvoice;
|
||||
|
||||
use App\DataMapper\Analytics\SendRecurringFailure;
|
||||
use App\Events\Invoice\InvoiceWasEmailed;
|
||||
use App\Factory\InvoiceInvitationFactory;
|
||||
use App\Factory\RecurringInvoiceToInvoiceFactory;
|
||||
use App\Jobs\Entity\EmailEntity;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\MakesInvoiceValues;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@ -32,7 +34,8 @@ class SendRecurring implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
use GeneratesCounter;
|
||||
|
||||
use MakesHash;
|
||||
|
||||
public $recurring_invoice;
|
||||
|
||||
protected $db;
|
||||
@ -58,16 +61,6 @@ class SendRecurring implements ShouldQueue
|
||||
*/
|
||||
public function handle() : void
|
||||
{
|
||||
//reset all contacts here
|
||||
// $this->recurring_invoice->client->contacts()->update(['send_email' => false]);
|
||||
|
||||
// $this->recurring_invoice->invitations->each(function ($invitation){
|
||||
|
||||
// $contact = $invitation->contact;
|
||||
// $contact->send_email = true;
|
||||
// $contact->save();
|
||||
|
||||
// });
|
||||
|
||||
// Generate Standard Invoice
|
||||
$invoice = RecurringInvoiceToInvoiceFactory::create($this->recurring_invoice, $this->recurring_invoice->client);
|
||||
@ -86,10 +79,12 @@ class SendRecurring implements ShouldQueue
|
||||
$invoice = $invoice->service()
|
||||
->markSent()
|
||||
->applyNumber()
|
||||
->createInvitations() //need to only link invitations to those in the recurring invoice
|
||||
// ->createInvitations() //need to only link invitations to those in the recurring invoice
|
||||
->fillDefaults()
|
||||
->save();
|
||||
|
||||
|
||||
$invoice = $this->createRecurringInvitations($invoice);
|
||||
|
||||
}
|
||||
else{
|
||||
|
||||
@ -154,6 +149,28 @@ class SendRecurring implements ShouldQueue
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Only create the invitations that are defined on the recurring invoice.
|
||||
* @param Invoice $invoice
|
||||
* @return Invoice $invoice
|
||||
*/
|
||||
private function createRecurringInvitations($invoice) :Invoice
|
||||
{
|
||||
|
||||
$this->recurring_invoice->invitations->each(function ($recurring_invitation) use($invoice){
|
||||
|
||||
$ii = InvoiceInvitationFactory::create($invoice->company_id, $invoice->user_id);
|
||||
$ii->key = $this->createDbHash(config('database.default'));
|
||||
$ii->invoice_id = $invoice->id;
|
||||
$ii->client_contact_id = $recurring_invitation->client_contact_id;
|
||||
$ii->save();
|
||||
|
||||
});
|
||||
|
||||
|
||||
return $invoice->fresh();
|
||||
}
|
||||
|
||||
public function failed($exception = null)
|
||||
{
|
||||
nlog('the job failed');
|
||||
|
@ -69,7 +69,7 @@ class SupportMessageSent extends Mailable
|
||||
if(Ninja::isHosted())
|
||||
$subject = "{$priority}Hosted-{$db}-{$is_large}{$platform}{$migrated} :: {$plan} :: ".date('M jS, g:ia');
|
||||
else
|
||||
$subject = "{$priority}Self Hosted :: {$plan} :: {$platform} :: ".date('M jS, g:ia');
|
||||
$subject = "{$priority}Self Hosted :: {$plan} :: {$is_large}{$platform}{$migrated} :: ".date('M jS, g:ia');
|
||||
|
||||
return $this->from(config('mail.from.address'), $user->present()->name())
|
||||
->replyTo($user->email, $user->present()->name())
|
||||
|
@ -308,7 +308,7 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->get();
|
||||
|
||||
$invoices->each(function ($invoice) {
|
||||
$invoice->service()->removeUnpaidGatewayFees();
|
||||
$invoice->service()->removeUnpaidGatewayFees()->save();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -222,15 +222,15 @@ class BaseRepository
|
||||
$this->saveDocuments($data['documents'], $model);
|
||||
|
||||
/* Marks whether the client contact should receive emails based on the send_email property */
|
||||
if (isset($data['client_contacts'])) {
|
||||
foreach ($data['client_contacts'] as $contact) {
|
||||
if ($contact['send_email'] == 1 && is_string($contact['id'])) {
|
||||
$client_contact = ClientContact::find($this->decodePrimaryKey($contact['id']));
|
||||
$client_contact->send_email = true;
|
||||
$client_contact->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (isset($data['client_contacts'])) {
|
||||
// foreach ($data['client_contacts'] as $contact) {
|
||||
// if ($contact['send_email'] == 1 && is_string($contact['id'])) {
|
||||
// $client_contact = ClientContact::find($this->decodePrimaryKey($contact['id']));
|
||||
// $client_contact->send_email = true;
|
||||
// $client_contact->save();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/* If invitations are present we need to filter existing invitations with the new ones */
|
||||
if (isset($data['invitations'])) {
|
||||
@ -285,10 +285,8 @@ class BaseRepository
|
||||
}
|
||||
}
|
||||
|
||||
$model->load('invitations');
|
||||
|
||||
/* If no invitations have been created, this is our fail safe to maintain state*/
|
||||
if ($model->invitations->count() == 0)
|
||||
if ($model->invitations()->count() == 0)
|
||||
$model->service()->createInvitations();
|
||||
|
||||
/* Recalculate invoice amounts */
|
||||
|
@ -494,6 +494,6 @@ class InvoiceService
|
||||
{
|
||||
$this->invoice->saveQuietly();
|
||||
|
||||
return $this->invoice;
|
||||
return $this->invoice->fresh();
|
||||
}
|
||||
}
|
||||
|
@ -86,8 +86,8 @@ class MarkPaid extends AbstractService
|
||||
->deletePdf()
|
||||
->save();
|
||||
|
||||
if ($this->invoice->client->getSetting('client_manual_payment_notification'))
|
||||
$payment->service()->sendEmail();
|
||||
// if ($this->invoice->client->getSetting('client_manual_payment_notification'))
|
||||
// $payment->service()->sendEmail();
|
||||
|
||||
/* Update Invoice balance */
|
||||
event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||
|
@ -33,15 +33,18 @@ class MarkSent extends AbstractService
|
||||
{
|
||||
|
||||
/* Return immediately if status is not draft */
|
||||
if ($this->invoice->status_id != Invoice::STATUS_DRAFT) {
|
||||
if ($this->invoice->fresh()->status_id != Invoice::STATUS_DRAFT) {
|
||||
return $this->invoice;
|
||||
}
|
||||
|
||||
$this->invoice->markInvitationsSent();
|
||||
|
||||
/*Set status*/
|
||||
$this->invoice
|
||||
->service()
|
||||
->setStatus(Invoice::STATUS_SENT)
|
||||
->save();
|
||||
|
||||
$this->invoice
|
||||
->service()
|
||||
->applyNumber()
|
||||
->setDueDate()
|
||||
->updateBalance($this->invoice->amount)
|
||||
@ -49,9 +52,18 @@ class MarkSent extends AbstractService
|
||||
->setReminder()
|
||||
->save();
|
||||
|
||||
$this->client->service()->updateBalance($this->invoice->balance)->save();
|
||||
$this->invoice->markInvitationsSent();
|
||||
|
||||
$this->invoice->ledger()->updateInvoiceBalance($this->invoice->balance, "Invoice {$this->invoice->number} marked as sent.");
|
||||
/*Adjust client balance*/
|
||||
$this->client
|
||||
->service()
|
||||
->updateBalance($this->invoice->balance)
|
||||
->save();
|
||||
|
||||
/*Update ledger*/
|
||||
$this->invoice
|
||||
->ledger()
|
||||
->updateInvoiceBalance($this->invoice->balance, "Invoice {$this->invoice->number} marked as sent.");
|
||||
|
||||
event(new InvoiceWasUpdated($this->invoice, $this->invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||
|
||||
|
@ -13,6 +13,8 @@
|
||||
namespace App\Services\Quote;
|
||||
|
||||
use App\Factory\CloneQuoteToInvoiceFactory;
|
||||
use App\Factory\InvoiceInvitationFactory;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Quote;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
@ -39,14 +41,20 @@ class ConvertQuote
|
||||
{
|
||||
$invoice = CloneQuoteToInvoiceFactory::create($quote, $quote->user_id);
|
||||
$invoice->design_id = $this->decodePrimaryKey($this->client->getSetting('invoice_design_id'));
|
||||
$invoice = $this->invoice_repo->save($invoice->toArray(), $invoice);
|
||||
|
||||
//create invitations here before the repo save()
|
||||
//we need to do this here otherwise the repo_save will create
|
||||
//invitations for ALL contacts
|
||||
$invites = $this->createConversionInvitations($invoice, $quote);
|
||||
$invoice_array = $invoice->toArray();
|
||||
$invoice_array['invitations'] = $invites;
|
||||
|
||||
$invoice = $this->invoice_repo->save($invoice_array, $invoice);
|
||||
|
||||
$invoice->fresh();
|
||||
|
||||
$invoice->service()
|
||||
->fillDefaults()
|
||||
// ->markSent()
|
||||
// ->createInvitations()
|
||||
->save();
|
||||
|
||||
$quote->invoice_id = $invoice->id;
|
||||
@ -56,4 +64,26 @@ class ConvertQuote
|
||||
// maybe should return invoice here
|
||||
return $invoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only create the invitations that are defined on the quote.
|
||||
*
|
||||
* @return Invoice $invoice
|
||||
*/
|
||||
private function createConversionInvitations($invoice, $quote)
|
||||
{
|
||||
$invites = [];
|
||||
|
||||
foreach($quote->invitations as $quote_invitation){
|
||||
|
||||
$ii = InvoiceInvitationFactory::create($invoice->company_id, $invoice->user_id);
|
||||
$ii->key = $this->createDbHash(config('database.default'));
|
||||
$ii->client_contact_id = $quote_invitation->client_contact_id;
|
||||
|
||||
$invites[] = $ii;
|
||||
}
|
||||
|
||||
return $invites;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Services\Quote;
|
||||
|
||||
use App\Events\Quote\QuoteWasApproved;
|
||||
use App\Factory\InvoiceInvitationFactory;
|
||||
use App\Jobs\Util\UnlinkFile;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Quote;
|
||||
@ -117,7 +118,6 @@ class QuoteService
|
||||
$this->invoice
|
||||
->service()
|
||||
->markSent()
|
||||
->createInvitations()
|
||||
->deletePdf()
|
||||
->save();
|
||||
|
||||
|
@ -54,8 +54,6 @@ class RecurringService
|
||||
return $this;
|
||||
}
|
||||
|
||||
// $this->createInvitations()->setStatus(RecurringInvoice::STATUS_ACTIVE);
|
||||
|
||||
$this->setStatus(RecurringInvoice::STATUS_ACTIVE);
|
||||
|
||||
return $this;
|
||||
|
@ -4328,6 +4328,9 @@ $LANG = array(
|
||||
'giropay_law' => 'By entering your Customer information (such as name, sort code and account number) you (the Customer) agree that this information is given voluntarily.',
|
||||
'eps' => 'EPS',
|
||||
'you_need_to_accept_the_terms_before_proceeding' => 'You need to accept the terms before proceeding.',
|
||||
'clone_to_expense' => 'Clone to expense',
|
||||
'checkout' => 'Checkout',
|
||||
|
||||
);
|
||||
|
||||
return $LANG;
|
||||
|
@ -90,7 +90,7 @@
|
||||
<div class="col-span-12 xl:col-span-4 bg-white flex flex-col items-center lg:h-screen">
|
||||
<div class="w-full p-10 md:p-24 xl:mt-32 md:max-w-3xl">
|
||||
<div class="col-span-12 w-full xl:col-span-9">
|
||||
<h2 class="text-2xl font-bold tracking-wide">{{ $heading_text ?? ctrans('texts.login') }}</h2>
|
||||
<h2 class="text-2xl font-bold tracking-wide">{{ $heading_text ?? ctrans('texts.checkout') }}</h2>
|
||||
@if (session()->has('message'))
|
||||
@component('portal.ninja2020.components.message')
|
||||
{{ session('message') }}
|
||||
|
@ -215,7 +215,7 @@ Route::match(['get', 'post'], 'payment_notification_webhook/{company_key}/{compa
|
||||
->middleware(['guest'])
|
||||
->name('payment_notification_webhook');
|
||||
|
||||
Route::post('api/v1/postmark_webhook', 'PostMarkController@webhook');
|
||||
Route::post('api/v1/postmark_webhook', 'PostMarkController@webhook')->middleware(['throttle:5000,1']);
|
||||
Route::get('token_hash_router', 'OneTimeTokenController@router');
|
||||
Route::get('webcron', 'WebCronController@index');
|
||||
Route::post('api/v1/get_migration_account', 'HostedMigrationController@getAccount')->middleware('guest');
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use App\DataMapper\ClientRegistrationFields;
|
||||
use App\DataMapper\ClientSettings;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Factory\CompanyUserFactory;
|
||||
@ -173,6 +174,8 @@ trait MockAccountData
|
||||
'account_id' => $this->account->id,
|
||||
]);
|
||||
|
||||
$this->company->client_registration_fields = ClientRegistrationFields::generate();
|
||||
|
||||
Storage::makeDirectory($this->company->company_key.'/documents', 0755, true);
|
||||
Storage::makeDirectory($this->company->company_key.'/images', 0755, true);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user