Merge pull request #6865 from turbo124/v5-develop

Fixes for converting quotes to invoices - invitations
This commit is contained in:
David Bomba 2021-10-19 20:04:45 +11:00 committed by GitHub
commit 0c23c058c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 107 additions and 44 deletions

View File

@ -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';

View File

@ -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');

View File

@ -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())

View File

@ -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();
});
}

View File

@ -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 */

View File

@ -494,6 +494,6 @@ class InvoiceService
{
$this->invoice->saveQuietly();
return $this->invoice;
return $this->invoice->fresh();
}
}

View File

@ -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)));

View File

@ -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)));

View File

@ -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;
}
}

View File

@ -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();

View File

@ -54,8 +54,6 @@ class RecurringService
return $this;
}
// $this->createInvitations()->setStatus(RecurringInvoice::STATUS_ACTIVE);
$this->setStatus(RecurringInvoice::STATUS_ACTIVE);
return $this;

View File

@ -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;

View File

@ -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') }}

View File

@ -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');

View File

@ -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);