1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 05:02:36 +01:00

Merge: Make automatic conversion of quote to invoice optional (#636)

This commit is contained in:
Hillel Coren 2016-01-20 10:41:57 +02:00
parent bf778aa616
commit 6166464003
16 changed files with 186 additions and 49 deletions

View File

@ -662,6 +662,7 @@ class AccountController extends BaseController
$account->invoice_terms = Input::get('invoice_terms');
$account->invoice_footer = Input::get('invoice_footer');
$account->quote_terms = Input::get('quote_terms');
$account->auto_convert_quote = Input::get('auto_convert_quote');
if (Input::has('recurring_hour')) {
$account->recurring_hour = Input::get('recurring_hour');

View File

@ -475,7 +475,7 @@ class InvoiceController extends BaseController
public function convertQuote($publicId)
{
$invoice = Invoice::with('invoice_items')->scope($publicId)->firstOrFail();
$clone = $this->invoiceService->approveQuote($invoice);
$clone = $this->invoiceService->convertQuote($invoice);
Session::flash('message', trans('texts.converted_to_invoice'));
return Redirect::to('invoices/'.$clone->public_id);

View File

@ -97,6 +97,9 @@ class PublicClientController extends BaseController
if ($invoice->due_date) {
$showApprove = time() < strtotime($invoice->due_date);
}
if ($invoice->invoice_status_id >= INVOICE_STATUS_APPROVED) {
$showApprove = false;
}
// Checkout.com requires first getting a payment token
$checkoutComToken = false;
@ -341,4 +344,4 @@ class PublicClientController extends BaseController
return $invitation;
}
}
}

View File

@ -131,7 +131,7 @@ class QuoteController extends BaseController
if ($action == 'convert') {
$invoice = Invoice::with('invoice_items')->scope($ids)->firstOrFail();
$clone = $this->invoiceService->approveQuote($invoice);
$clone = $this->invoiceService->convertQuote($invoice);
Session::flash('message', trans('texts.converted_to_invoice'));
return Redirect::to('invoices/'.$clone->public_id);

View File

@ -368,8 +368,9 @@ if (!defined('CONTACT_EMAIL')) {
define('INVOICE_STATUS_DRAFT', 1);
define('INVOICE_STATUS_SENT', 2);
define('INVOICE_STATUS_VIEWED', 3);
define('INVOICE_STATUS_PARTIAL', 4);
define('INVOICE_STATUS_PAID', 5);
define('INVOICE_STATUS_APPROVED', 4);
define('INVOICE_STATUS_PARTIAL', 5);
define('INVOICE_STATUS_PAID', 6);
define('PAYMENT_TYPE_CREDIT', 1);
define('CUSTOM_DESIGN', 11);

View File

@ -252,6 +252,14 @@ class Invoice extends EntityModel implements BalanceAffecting
}
}
public function markApproved()
{
if ($this->is_quote) {
$this->invoice_status_id = INVOICE_STATUS_APPROVED;
$this->save();
}
}
public function updateBalances($balanceAdjustment, $partial = 0)
{
if ($this->is_deleted) {

View File

@ -1,5 +1,6 @@
<?php namespace App\Services;
use Auth;
use Utils;
use URL;
use App\Services\BaseService;
@ -62,23 +63,42 @@ class InvoiceService extends BaseService
return $invoice;
}
public function convertQuote($quote, $invitation = null)
{
$invoice = $this->invoiceRepo->cloneInvoice($quote, $quote->id);
if (!$invitation) {
return $invoice;
}
foreach ($invoice->invitations as $invoiceInvitation) {
if ($invitation->contact_id == $invoiceInvitation->contact_id) {
return $invoiceInvitation->invitation_key;
}
}
}
public function approveQuote($quote, $invitation = null)
{
$account = Auth::user()->account;
if (!$quote->is_quote || $quote->quote_invoice_id) {
return null;
}
$invoice = $this->invoiceRepo->cloneInvoice($quote, $quote->id);
if ($account->auto_convert_quote) {
$invoice = $this->convertQuote($quote, $invitation);
event(new QuoteInvitationWasApproved($quote, $invoice, $invitation));
if (!$invitation) {
return $invoice;
}
} else {
$quote->markApproved();
event(new QuoteInvitationWasApproved($quote, $invoice, $invitation));
foreach ($invoice->invitations as $invoiceInvitation) {
if ($invitation->contact_id == $invoiceInvitation->contact_id) {
return $invoiceInvitation->invitation_key;
event(new QuoteInvitationWasApproved($quote, null, $invitation));
foreach ($quote->invitations as $invoiceInvitation) {
if ($invitation->contact_id == $invoiceInvitation->contact_id) {
return $invoiceInvitation->invitation_key;
}
}
}
}
@ -227,6 +247,9 @@ class InvoiceService extends BaseService
case INVOICE_STATUS_VIEWED:
$class = 'warning';
break;
case INVOICE_STATUS_APPROVED:
$class = 'success';
break;
case INVOICE_STATUS_PARTIAL:
$class = 'primary';
break;
@ -237,4 +260,4 @@ class InvoiceService extends BaseService
return "<h4><div class=\"label label-{$class}\">$label</div></h4>";
}
}
}

View File

@ -0,0 +1,46 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddQuoteToInvoiceOption extends Migration
{
/**
* Run the migrations.
* Make the conversion of a quote into an invoice automatically after a client approves optional.
*
* @return void
*/
public function up()
{
Schema::table('accounts', function (Blueprint $table) {
$table->boolean('auto_convert_quote')->default(true);
});
// we need to create the last status to resolve a foreign key constraint
DB::table('invoice_statuses')->insert([
'id' => 6,
'name' => 'Paid'
]);
DB::table('invoices')
->whereIn('invoice_status_id', [4, 5])
->increment('invoice_status_id');
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('accounts', function (Blueprint $table) {
$table->dropColumn('auto_convert_quote');
});
DB::table('invoices')
->whereIn('invoice_status_id', [5, 6])
->decrement('invoice_status_id');
}
}

View File

@ -50,12 +50,6 @@ class ConstantsSeeder extends Seeder
Theme::create(array('name' => 'united'));
Theme::create(array('name' => 'yeti'));
InvoiceStatus::create(array('name' => 'Draft'));
InvoiceStatus::create(array('name' => 'Sent'));
InvoiceStatus::create(array('name' => 'Viewed'));
InvoiceStatus::create(array('name' => 'Partial'));
InvoiceStatus::create(array('name' => 'Paid'));
Frequency::create(array('name' => 'Weekly'));
Frequency::create(array('name' => 'Two weeks'));
Frequency::create(array('name' => 'Four weeks'));

View File

@ -1,23 +1,24 @@
<?php
class DatabaseSeeder extends Seeder {
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$this->command->info('Running DatabaseSeeder');
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$this->command->info('Running DatabaseSeeder');
Eloquent::unguard();
Eloquent::unguard();
$this->call('ConstantsSeeder');
$this->call('CountriesSeeder');
$this->call('PaymentLibrariesSeeder');
$this->call('ConstantsSeeder');
$this->call('CountriesSeeder');
$this->call('PaymentLibrariesSeeder');
$this->call('FontsSeeder');
$this->call('BanksSeeder');
}
}
$this->call('FontsSeeder');
$this->call('InvoiceStatusSeeder');
}
}

View File

@ -0,0 +1,38 @@
<?php
use App\Models\InvoiceStatus;
class InvoiceStatusSeeder extends Seeder
{
public function run()
{
Eloquent::unguard();
$this->createInvoiceStatuses();
Eloquent::reguard();
}
private function createInvoiceStatuses()
{
$statuses = [
['id' => '1', 'name' => 'Draft'],
['id' => '2', 'name' => 'Sent'],
['id' => '3', 'name' => 'Viewed'],
['id' => '4', 'name' => 'Approved'],
['id' => '5', 'name' => 'Partial'],
['id' => '6', 'name' => 'Paid'],
];
foreach ($statuses as $status) {
$record = InvoiceStatus::find($status['id']);
if ($record) {
$record->name = $status['name'];
$record->save();
} else {
InvoiceStatus::create($status);
}
}
}
}

View File

@ -30394,8 +30394,9 @@ var CONSTS = {};
CONSTS.INVOICE_STATUS_DRAFT = 1;
CONSTS.INVOICE_STATUS_SENT = 2;
CONSTS.INVOICE_STATUS_VIEWED = 3;
CONSTS.INVOICE_STATUS_PARTIAL = 4;
CONSTS.INVOICE_STATUS_PAID = 5;
CONSTS.INVOICE_STATUS_APPROVED = 4;
CONSTS.INVOICE_STATUS_PARTIAL = 5;
CONSTS.INVOICE_STATUS_PAID = 6;
$.fn.datepicker.defaults.autoclose = true;
$.fn.datepicker.defaults.todayHighlight = true;
@ -30870,6 +30871,7 @@ function actionListHandler() {
}
});
}
var NINJA = NINJA || {};
NINJA.TEMPLATES = {

View File

@ -516,8 +516,9 @@ var CONSTS = {};
CONSTS.INVOICE_STATUS_DRAFT = 1;
CONSTS.INVOICE_STATUS_SENT = 2;
CONSTS.INVOICE_STATUS_VIEWED = 3;
CONSTS.INVOICE_STATUS_PARTIAL = 4;
CONSTS.INVOICE_STATUS_PAID = 5;
CONSTS.INVOICE_STATUS_APPROVED = 4;
CONSTS.INVOICE_STATUS_PARTIAL = 5;
CONSTS.INVOICE_STATUS_PAID = 6;
$.fn.datepicker.defaults.autoclose = true;
$.fn.datepicker.defaults.todayHighlight = true;
@ -991,4 +992,4 @@ function actionListHandler() {
$(this).closest('tr').find('.tr-status').show();
}
});
}
}

View File

@ -1054,5 +1054,9 @@ return array(
'username' => 'Username',
'account_number' => 'Account Number',
'bank_account_error' => 'Failed to retreive account details, please check your credentials.',
);
'status_approved' => 'Approved',
'quote_settings' => 'Quote Settings',
'auto_convert_quote' => 'Auto convert quote',
'auto_convert_quote_help' => 'When a client approves a quote automatically convert it to an invoice.',
);

View File

@ -390,6 +390,7 @@ return array(
'notification_quote_viewed_subject' => 'Offerte :invoice is bekeken door :client',
'notification_quote_sent' => 'Klant :client heeft offerte :invoice voor :amount per email ontvangen.',
'notification_quote_viewed' => 'Klant :client heeft offerte :invoice voor :amount bekeken.',
'auto_convert_quote' => 'Offerte automatisch omzetten in factuur als deze goed gekeurd wordt',
'session_expired' => 'Uw sessie is verlopen.',
@ -757,6 +758,7 @@ return array(
'status_draft' => 'Concept',
'status_sent' => 'Verstuurd',
'status_viewed' => 'Bekeken',
'status_approved' => 'Goedgekeurd',
'status_partial' => 'Gedeeltelijk',
'status_paid' => 'Betaald',
'show_line_item_tax' => '<b>BTW-tarieven per regel</b> tonen',

View File

@ -20,10 +20,11 @@
@parent
@include('accounts.nav', ['selected' => ACCOUNT_INVOICE_SETTINGS, 'advanced' => true])
{!! Former::open()->rules(['iframe_url' => 'url'])->addClass('warn-on-exit') !!}
{{ Former::populate($account) }}
{{ Former::populateField('custom_invoice_taxes1', intval($account->custom_invoice_taxes1)) }}
{{ Former::populateField('custom_invoice_taxes2', intval($account->custom_invoice_taxes2)) }}
{!! Former::open()->rules(['iframe_url' => 'url'])->addClass('warn-on-exit') !!}
{{ Former::populate($account) }}
{{ Former::populateField('auto_convert_quote', intval($account->auto_convert_quote)) }}
{{ Former::populateField('custom_invoice_taxes1', intval($account->custom_invoice_taxes1)) }}
{{ Former::populateField('custom_invoice_taxes2', intval($account->custom_invoice_taxes2)) }}
{{ Former::populateField('share_counter', intval($account->share_counter)) }}
<div class="panel panel-default">
@ -97,6 +98,7 @@
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
@ -172,6 +174,17 @@
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{!! trans('texts.quote_settings') !!}</h3>
</div>
<div class="panel-body form-padding-right">
{!! Former::checkbox('auto_convert_quote')
->text(trans('texts.enable'))
->blockHelp(trans('texts.auto_convert_quote_help')) !!}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{!! trans('texts.default_messages') !!}</h3>
@ -304,4 +317,4 @@
@section('onReady')
$('#custom_invoice_label1').focus();
@stop
@stop