mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-03 16:14:39 -04:00
Allow conversion of quotes to invoices (#3760)
This commit is contained in:
parent
8512db6b1e
commit
c72d38ca4f
@ -28,14 +28,14 @@ class CloneQuoteToInvoiceFactory
|
|||||||
unset($quote_array['hashed_id']);
|
unset($quote_array['hashed_id']);
|
||||||
unset($quote_array['invoice_id']);
|
unset($quote_array['invoice_id']);
|
||||||
unset($quote_array['id']);
|
unset($quote_array['id']);
|
||||||
|
|
||||||
foreach($quote_array as $key => $value)
|
foreach($quote_array as $key => $value)
|
||||||
$invoice->{$key} = $value;
|
$invoice->{$key} = $value;
|
||||||
|
|
||||||
|
$invoice->status_id = Invoice::STATUS_DRAFT;
|
||||||
$invoice->due_date = null;
|
$invoice->due_date = null;
|
||||||
$invoice->partial_due_date = null;
|
$invoice->partial_due_date = null;
|
||||||
$invoice->number = null;
|
$invoice->number = null;
|
||||||
$invoice->status_id = null;
|
|
||||||
|
|
||||||
return $invoice;
|
return $invoice;
|
||||||
|
|
||||||
|
@ -82,6 +82,11 @@ class QuoteFilters extends QueryFilters
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function number($number = '')
|
||||||
|
{
|
||||||
|
return $this->builder->where('number', 'like', '%'.$number.'%');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts the list based on $sort
|
* Sorts the list based on $sort
|
||||||
*
|
*
|
||||||
|
@ -41,7 +41,7 @@ class InvitationController extends Controller
|
|||||||
if ((bool)$invitation->contact->client->getSetting('enable_client_portal_password') !== false) {
|
if ((bool)$invitation->contact->client->getSetting('enable_client_portal_password') !== false) {
|
||||||
$this->middleware('auth:contact');
|
$this->middleware('auth:contact');
|
||||||
} else {
|
} else {
|
||||||
auth()->guard('contact')->login($invitation->contact, false);
|
auth()->guard('contact')->login($invitation->contact, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!request()->has('silent')) {
|
if (!request()->has('silent')) {
|
||||||
|
@ -23,13 +23,13 @@ class SwitchCompanyController extends Controller
|
|||||||
|
|
||||||
public function __invoke(string $contact)
|
public function __invoke(string $contact)
|
||||||
{
|
{
|
||||||
$client_contact = ClientContact::query()
|
|
||||||
->where('user_id', auth()->user()->id)
|
$client_contact = ClientContact::where('email', auth()->user()->email)
|
||||||
->where('id', $this->transformKeys($contact))
|
->where('id', $this->transformKeys($contact))
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
Auth::guard('contact')->login($client_contact, true);
|
Auth::guard('contact')->login($client_contact, true);
|
||||||
|
|
||||||
return back();
|
return redirect('/client/dashboard');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,7 +366,7 @@ class MigrationController extends BaseController
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StartMigration::dispatch(base_path("storage/app/public/$migration_file"), $user, $company);
|
StartMigration::dispatch(base_path("storage/app/public/$migration_file"), $user, $company)->delay(now()->addSeconds(60));
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'_id' => Str::uuid(),
|
'_id' => Str::uuid(),
|
||||||
|
@ -49,7 +49,8 @@ class PortalComposer
|
|||||||
$data['company'] = auth()->user()->company;
|
$data['company'] = auth()->user()->company;
|
||||||
$data['client'] = auth()->user()->client;
|
$data['client'] = auth()->user()->client;
|
||||||
$data['settings'] = auth()->user()->client->getMergedSettings();
|
$data['settings'] = auth()->user()->client->getMergedSettings();
|
||||||
$data['multiple_contacts'] = ClientContact::where('email', auth('contact')->user()->email)->get();
|
|
||||||
|
$data['multiple_contacts'] = ClientContact::where('email', auth('contact')->user()->email)->whereNotNull('email')->distinct('company_id')->get();
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,12 @@ class EntityPaidMailer extends BaseMailerJob implements ShouldQueue
|
|||||||
{
|
{
|
||||||
info("entity paid mailer");
|
info("entity paid mailer");
|
||||||
//Set DB
|
//Set DB
|
||||||
|
//
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
|
if($this->company->company_users->first()->is_migrating)
|
||||||
|
return true;
|
||||||
|
|
||||||
//if we need to set an email driver do it now
|
//if we need to set an email driver do it now
|
||||||
$this->setMailDriver($this->payment->client->getSetting('email_sending_method'));
|
$this->setMailDriver($this->payment->client->getSetting('email_sending_method'));
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ use App\Libraries\MultiDB;
|
|||||||
use App\Mail\MigrationCompleted;
|
use App\Mail\MigrationCompleted;
|
||||||
use App\Mail\MigrationFailed;
|
use App\Mail\MigrationFailed;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
|
use App\Models\ClientContact;
|
||||||
use App\Models\ClientGatewayToken;
|
use App\Models\ClientGatewayToken;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\CompanyGateway;
|
use App\Models\CompanyGateway;
|
||||||
@ -147,7 +148,7 @@ class Import implements ShouldQueue
|
|||||||
* @return void
|
* @return void
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle() :bool
|
||||||
{
|
{
|
||||||
|
|
||||||
set_time_limit(0);
|
set_time_limit(0);
|
||||||
@ -156,7 +157,6 @@ class Import implements ShouldQueue
|
|||||||
if (! in_array($key, $this->available_imports)) {
|
if (! in_array($key, $this->available_imports)) {
|
||||||
//throw new ResourceNotAvailableForMigration("Resource {$key} is not available for migration.");
|
//throw new ResourceNotAvailableForMigration("Resource {$key} is not available for migration.");
|
||||||
info("Resource {$key} is not available for migration.");
|
info("Resource {$key} is not available for migration.");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,6 +170,8 @@ class Import implements ShouldQueue
|
|||||||
Mail::to($this->user)->send(new MigrationCompleted());
|
Mail::to($this->user)->send(new MigrationCompleted());
|
||||||
|
|
||||||
info('Completed🚀🚀🚀🚀🚀 at '.now());
|
info('Completed🚀🚀🚀🚀🚀 at '.now());
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -368,7 +370,9 @@ class Import implements ShouldQueue
|
|||||||
unset($modified_contacts[$key]['id']);
|
unset($modified_contacts[$key]['id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$contact_repository->save($modified_contacts, $client);
|
$saveable_contacts['contacts'] = $modified_contacts;
|
||||||
|
|
||||||
|
$contact_repository->save($saveable_contacts, $client);
|
||||||
}
|
}
|
||||||
|
|
||||||
$key = "clients_{$resource['id']}";
|
$key = "clients_{$resource['id']}";
|
||||||
|
@ -74,6 +74,9 @@ class StartMigration implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
set_time_limit(0);
|
||||||
|
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
auth()->login($this->user, false);
|
auth()->login($this->user, false);
|
||||||
@ -96,7 +99,7 @@ class StartMigration implements ShouldQueue
|
|||||||
$zip->close();
|
$zip->close();
|
||||||
|
|
||||||
if (app()->environment() == 'testing') {
|
if (app()->environment() == 'testing') {
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->company->setMigration(true);
|
$this->company->setMigration(true);
|
||||||
@ -110,6 +113,9 @@ class StartMigration implements ShouldQueue
|
|||||||
$data = json_decode(file_get_contents($file), 1);
|
$data = json_decode(file_get_contents($file), 1);
|
||||||
|
|
||||||
Import::dispatchNow($data, $this->company, $this->user);
|
Import::dispatchNow($data, $this->company, $this->user);
|
||||||
|
|
||||||
|
$this->company->setMigration(false);
|
||||||
|
|
||||||
} catch (NonExistingMigrationFile | ProcessingMigrationArchiveFailed | ResourceNotAvailableForMigration | MigrationValidatorFailed | ResourceDependencyMissing $e) {
|
} catch (NonExistingMigrationFile | ProcessingMigrationArchiveFailed | ResourceNotAvailableForMigration | MigrationValidatorFailed | ResourceDependencyMissing $e) {
|
||||||
$this->company->setMigration(false);
|
$this->company->setMigration(false);
|
||||||
|
|
||||||
@ -119,6 +125,11 @@ class StartMigration implements ShouldQueue
|
|||||||
info($e->getMessage());
|
info($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//always make sure we unset the migration as running
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function failed($exception = null)
|
public function failed($exception = null)
|
||||||
|
@ -37,18 +37,27 @@ class SubscriptionHandler implements ShouldQueue
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle() :bool
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if(!$this->entity->company || $this->entity->company->company_users->first()->is_migrating)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
info("i got past the check");
|
||||||
|
|
||||||
$subscriptions = Subscription::where('company_id', $this->entity->company_id)
|
$subscriptions = Subscription::where('company_id', $this->entity->company_id)
|
||||||
->where('event_id', $this->event_id)
|
->where('event_id', $this->event_id)
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
if(!$subscriptions || $subscriptions->count() == 0)
|
if(!$subscriptions || $subscriptions->count() == 0)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
$subscriptions->each(function($subscription) {
|
$subscriptions->each(function($subscription) {
|
||||||
$this->process($subscription);
|
$this->process($subscription);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function process($subscription)
|
private function process($subscription)
|
||||||
|
@ -48,6 +48,9 @@ class PaymentNotification implements ShouldQueue
|
|||||||
/*User notifications*/
|
/*User notifications*/
|
||||||
foreach ($payment->company->company_users as $company_user) {
|
foreach ($payment->company->company_users as $company_user) {
|
||||||
|
|
||||||
|
if($company_user->is_migrating)
|
||||||
|
return true;
|
||||||
|
|
||||||
$user = $company_user->user;
|
$user = $company_user->user;
|
||||||
|
|
||||||
$methods = $this->findUserEntityNotificationType($payment, $company_user, ['all_notifications']);
|
$methods = $this->findUserEntityNotificationType($payment, $company_user, ['all_notifications']);
|
||||||
|
@ -406,9 +406,13 @@ class Company extends BaseModel
|
|||||||
|
|
||||||
public function setMigration($status)
|
public function setMigration($status)
|
||||||
{
|
{
|
||||||
$this->company_users->each(function ($cu) use ($status) {
|
$company_users = CompanyUser::where('company_id', $this->id)->get();
|
||||||
|
|
||||||
|
foreach($company_users as $cu)
|
||||||
|
{
|
||||||
$cu->is_migrating=$status;
|
$cu->is_migrating=$status;
|
||||||
$cu->save();
|
$cu->save();
|
||||||
});
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ class ClientContactRepository extends BaseRepository
|
|||||||
{
|
{
|
||||||
public function save(array $data, Client $client) : void
|
public function save(array $data, Client $client) : void
|
||||||
{
|
{
|
||||||
|
|
||||||
if (isset($data['contacts'])) {
|
if (isset($data['contacts'])) {
|
||||||
$contacts = collect($data['contacts']);
|
$contacts = collect($data['contacts']);
|
||||||
} else {
|
} else {
|
||||||
@ -66,17 +67,20 @@ class ClientContactRepository extends BaseRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
$update_contact->save();
|
$update_contact->save();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//always made sure we have one blank contact to maintain state
|
//always made sure we have one blank contact to maintain state
|
||||||
if ($contacts->count() == 0) {
|
if ($client->contacts->count() == 0) {
|
||||||
|
|
||||||
|
info("no contacts found");
|
||||||
|
|
||||||
$new_contact = ClientContactFactory::create($client->company_id, $client->user_id);
|
$new_contact = ClientContactFactory::create($client->company_id, $client->user_id);
|
||||||
$new_contact->client_id = $client->id;
|
$new_contact->client_id = $client->id;
|
||||||
$new_contact->contact_key = Str::random(40);
|
$new_contact->contact_key = Str::random(40);
|
||||||
$new_contact->is_primary = true;
|
$new_contact->is_primary = true;
|
||||||
$new_contact->save();
|
$new_contact->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,10 @@ class ConvertQuote
|
|||||||
private $client;
|
private $client;
|
||||||
private $invoice_repo;
|
private $invoice_repo;
|
||||||
|
|
||||||
public function __construct($client, InvoiceRepository $invoice_repo)
|
public function __construct($client)
|
||||||
{
|
{
|
||||||
$this->client = $client;
|
$this->client = $client;
|
||||||
$this->invoice_repo = $invoice_repo;
|
$this->invoice_repo = new InvoiceRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,9 +23,19 @@ class ConvertQuote
|
|||||||
public function run($quote)
|
public function run($quote)
|
||||||
{
|
{
|
||||||
$invoice = CloneQuoteToInvoiceFactory::create($quote, $quote->user_id, $quote->company_id);
|
$invoice = CloneQuoteToInvoiceFactory::create($quote, $quote->user_id, $quote->company_id);
|
||||||
$this->invoice_repo->save([], $invoice);
|
$invoice = $this->invoice_repo->save([], $invoice);
|
||||||
|
|
||||||
|
$invoice->fresh();
|
||||||
|
|
||||||
|
$invoice->service()
|
||||||
|
->markSent()
|
||||||
|
->createInvitations()
|
||||||
|
->save();
|
||||||
|
|
||||||
|
$quote->invoice_id = $invoice->id;
|
||||||
|
$quote->save();
|
||||||
|
|
||||||
// maybe should return invoice here
|
// maybe should return invoice here
|
||||||
return $quote;
|
return $invoice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ class QuoteService
|
|||||||
{
|
{
|
||||||
protected $quote;
|
protected $quote;
|
||||||
|
|
||||||
|
public $invoice;
|
||||||
|
|
||||||
public function __construct($quote)
|
public function __construct($quote)
|
||||||
{
|
{
|
||||||
$this->quote = $quote;
|
$this->quote = $quote;
|
||||||
@ -38,17 +40,28 @@ class QuoteService
|
|||||||
public function markApproved()
|
public function markApproved()
|
||||||
{
|
{
|
||||||
$mark_approved = new MarkApproved($this->quote->client);
|
$mark_approved = new MarkApproved($this->quote->client);
|
||||||
|
|
||||||
$this->quote = $mark_approved->run($this->quote);
|
$this->quote = $mark_approved->run($this->quote);
|
||||||
|
|
||||||
if ($this->quote->client->getSetting('auto_convert_quote') === true) {
|
if ($this->quote->client->getSetting('auto_convert_quote') === true) {
|
||||||
$convert_quote = new ConvertQuote($this->quote->client);
|
$this->convert();
|
||||||
$this->quote = $convert_quote->run($this->quote);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function convert() :QuoteService
|
||||||
|
{
|
||||||
|
if($this->quote->invoice_id)
|
||||||
|
return $this;
|
||||||
|
|
||||||
|
$convert_quote = new ConvertQuote($this->quote->client);
|
||||||
|
$this->invoice = $convert_quote->run($this->quote);
|
||||||
|
|
||||||
|
$this->quote->fresh();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function getQuotePdf($contact = null)
|
public function getQuotePdf($contact = null)
|
||||||
{
|
{
|
||||||
$get_invoice_pdf = new GetQuotePdf();
|
$get_invoice_pdf = new GetQuotePdf();
|
||||||
@ -101,8 +114,7 @@ class QuoteService
|
|||||||
$invoice = null;
|
$invoice = null;
|
||||||
|
|
||||||
if ($this->quote->client->getSetting('auto_convert_quote')) {
|
if ($this->quote->client->getSetting('auto_convert_quote')) {
|
||||||
$invoice = $this->convertToInvoice();
|
$this->convert();
|
||||||
$this->linkInvoiceToQuote($invoice)->save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->quote->client->getSetting('auto_archive_quote')) {
|
if ($this->quote->client->getSetting('auto_archive_quote')) {
|
||||||
@ -113,32 +125,16 @@ class QuoteService
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Where we convert a quote to an invoice we link the two entities via the invoice_id parameter on the quote table
|
|
||||||
* @param object $invoice The Invoice object
|
|
||||||
* @return object QuoteService
|
|
||||||
*/
|
|
||||||
public function linkInvoiceToQuote($invoice) :QuoteService
|
|
||||||
{
|
|
||||||
$this->quote->invoice_id = $invoice->id;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function convertToInvoice() :Invoice
|
public function convertToInvoice() :Invoice
|
||||||
{
|
{
|
||||||
|
|
||||||
$invoice = CloneQuoteToInvoiceFactory::create($this->quote, $this->quote->user_id);
|
//to prevent circular references we need to explicit call this here.
|
||||||
$invoice->status_id = Invoice::STATUS_SENT;
|
$mark_approved = new MarkApproved($this->quote->client);
|
||||||
$invoice->due_date = null;
|
$this->quote = $mark_approved->run($this->quote);
|
||||||
$invoice->number = null;
|
|
||||||
$invoice->save();
|
|
||||||
|
|
||||||
return $invoice->service()
|
$this->convert();
|
||||||
->markSent()
|
|
||||||
->createInvitations()
|
|
||||||
->save();
|
|
||||||
|
|
||||||
|
return $this->invoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -148,6 +144,7 @@ class QuoteService
|
|||||||
public function save() : ?Quote
|
public function save() : ?Quote
|
||||||
{
|
{
|
||||||
$this->quote->save();
|
$this->quote->save();
|
||||||
|
|
||||||
return $this->quote;
|
return $this->quote;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ class QuoteTransformer extends EntityTransformer
|
|||||||
'client_id' => (string) $this->encodePrimaryKey($quote->client_id),
|
'client_id' => (string) $this->encodePrimaryKey($quote->client_id),
|
||||||
'status_id' => (string)$quote->status_id,
|
'status_id' => (string)$quote->status_id,
|
||||||
'design_id' => (string) $this->encodePrimaryKey($quote->design_id),
|
'design_id' => (string) $this->encodePrimaryKey($quote->design_id),
|
||||||
'invoice_id' => (string)$quote->invoice_id,
|
'invoice_id' => (string)$this->encodePrimaryKey($quote->invoice_id),
|
||||||
'updated_at' => (int)$quote->updated_at,
|
'updated_at' => (int)$quote->updated_at,
|
||||||
'archived_at' => (int)$quote->deleted_at,
|
'archived_at' => (int)$quote->deleted_at,
|
||||||
'created_at' => (int)$quote->created_at,
|
'created_at' => (int)$quote->created_at,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"video": false,
|
"video": false,
|
||||||
"baseUrl": "http://127.0.0.1:8002/"
|
"baseUrl": "http://ninja.test:8000/"
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@
|
|||||||
<div class="col-span-6 sm:col-span-3">
|
<div class="col-span-6 sm:col-span-3">
|
||||||
<label for="street" class="input-label">@lang('texts.name')</label>
|
<label for="street" class="input-label">@lang('texts.name')</label>
|
||||||
<input id="name" class="input w-full" name="name"
|
<input id="name" class="input w-full" name="name"
|
||||||
value="{{ auth()->user()->client->name }}"/>
|
value="{{ auth()->user()->client->present()->name }}"/>
|
||||||
@error('name')
|
@error('name')
|
||||||
<div class="validation validation-fail">
|
<div class="validation validation-fail">
|
||||||
{{ $message }}
|
{{ $message }}
|
||||||
@ -229,7 +229,7 @@
|
|||||||
<select id="country" class="input w-full form-select" name="country">
|
<select id="country" class="input w-full form-select" name="country">
|
||||||
@foreach($countries as $country)
|
@foreach($countries as $country)
|
||||||
<option
|
<option
|
||||||
{{ $country == auth()->user()->client->country->id ? 'selected' : null }} value="{{ $country->id }}">
|
{{ $country == isset(auth()->user()->client->country->id) ? 'selected' : null }} value="{{ $country->id }}">
|
||||||
{{ $country->iso_3166_2 }}
|
{{ $country->iso_3166_2 }}
|
||||||
({{ $country->name }})
|
({{ $country->name }})
|
||||||
</option>
|
</option>
|
||||||
@ -333,7 +333,7 @@
|
|||||||
<select id="shipping_country" class="input w-full form-select" name="shipping_country">
|
<select id="shipping_country" class="input w-full form-select" name="shipping_country">
|
||||||
@foreach($countries as $country)
|
@foreach($countries as $country)
|
||||||
<option
|
<option
|
||||||
{{ $country == auth()->user()->client->shipping_country->id ? 'selected' : null }} value="{{ $country->id }}">
|
{{ $country == isset(auth()->user()->client->shipping_country->id) ? 'selected' : null }} value="{{ $country->id }}">
|
||||||
{{ $country->iso_3166_2 }}
|
{{ $country->iso_3166_2 }}
|
||||||
({{ $country->name }})
|
({{ $country->name }})
|
||||||
</option>
|
</option>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user