mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-04 02:47:34 -05:00 
			
		
		
		
	Support paying draft invoices
This commit is contained in:
		
							parent
							
								
									2da91729b3
								
							
						
					
					
						commit
						eebe61b4d0
					
				@ -9,7 +9,6 @@ use Cache;
 | 
			
		||||
use Redirect;
 | 
			
		||||
use DB;
 | 
			
		||||
use URL;
 | 
			
		||||
use DropdownButton;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
use App\Models\Client;
 | 
			
		||||
use App\Models\Account;
 | 
			
		||||
@ -123,46 +122,6 @@ class InvoiceController extends BaseController
 | 
			
		||||
            'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS),
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $actions = [
 | 
			
		||||
            ['url' => 'javascript:onCloneClick()', 'label' => trans("texts.clone_{$entityType}")],
 | 
			
		||||
            ['url' => URL::to("{$entityType}s/{$entityType}_history/{$invoice->public_id}"), 'label' => trans('texts.view_history')],
 | 
			
		||||
            DropdownButton::DIVIDER
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        if ($entityType == ENTITY_QUOTE) {
 | 
			
		||||
            if ($invoice->quote_invoice_id) {
 | 
			
		||||
                $actions[] = ['url' => URL::to("invoices/{$invoice->quote_invoice_id}/edit"), 'label' => trans('texts.view_invoice')];
 | 
			
		||||
            } else {
 | 
			
		||||
                $actions[] = ['url' => 'javascript:onConvertClick()', 'label' => trans('texts.convert_to_invoice')];
 | 
			
		||||
            }
 | 
			
		||||
        } elseif ($entityType == ENTITY_INVOICE) {
 | 
			
		||||
            if ($invoice->quote_id) {
 | 
			
		||||
                $actions[] = ['url' => URL::to("quotes/{$invoice->quote_id}/edit"), 'label' => trans('texts.view_quote')];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!$invoice->is_recurring && $invoice->balance > 0) {
 | 
			
		||||
                $actions[] = ['url' => 'javascript:submitBulkAction("markPaid")', 'label' => trans('texts.mark_paid')];
 | 
			
		||||
                if ($invoice->is_public) {
 | 
			
		||||
                    $actions[] = ['url' => 'javascript:onPaymentClick()', 'label' => trans('texts.enter_payment')];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach ($invoice->payments as $payment) {
 | 
			
		||||
                $label = trans('texts.view_payment');
 | 
			
		||||
                if (count($invoice->payments) > 1) {
 | 
			
		||||
                    $label .= ' - ' . $account->formatMoney($payment->amount, $invoice->client);
 | 
			
		||||
                }
 | 
			
		||||
                $actions[] = ['url' => $payment->present()->url, 'label' => $label];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (count($actions) > 3) {
 | 
			
		||||
            $actions[] = DropdownButton::DIVIDER;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $actions[] = ['url' => 'javascript:onArchiveClick()', 'label' => trans("texts.archive_{$entityType}")];
 | 
			
		||||
        $actions[] = ['url' => 'javascript:onDeleteClick()', 'label' => trans("texts.delete_{$entityType}")];
 | 
			
		||||
 | 
			
		||||
        $lastSent = ($invoice->is_recurring && $invoice->last_sent_date) ? $invoice->recurring_invoices->last() : null;
 | 
			
		||||
 | 
			
		||||
        if(!Auth::user()->hasPermission('view_all')){
 | 
			
		||||
@ -180,7 +139,6 @@ class InvoiceController extends BaseController
 | 
			
		||||
                'title' => trans("texts.edit_{$entityType}"),
 | 
			
		||||
                'client' => $invoice->client,
 | 
			
		||||
                'isRecurring' => $invoice->is_recurring,
 | 
			
		||||
                'actions' => $actions,
 | 
			
		||||
                'lastSent' => $lastSent];
 | 
			
		||||
        $data = array_merge($data, self::getViewModel($invoice));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -108,6 +108,9 @@ class PaymentApiController extends BaseAPIController
 | 
			
		||||
     */
 | 
			
		||||
    public function store(CreatePaymentAPIRequest $request)
 | 
			
		||||
    {
 | 
			
		||||
        // check payment has been marked sent
 | 
			
		||||
        $request->invoice->markSentIfUnsent();
 | 
			
		||||
 | 
			
		||||
        $payment = $this->paymentRepo->save($request->input());
 | 
			
		||||
 | 
			
		||||
        if (Input::get('email_receipt')) {
 | 
			
		||||
 | 
			
		||||
@ -85,7 +85,6 @@ class PaymentController extends BaseController
 | 
			
		||||
    {
 | 
			
		||||
        $invoices = Invoice::scope()
 | 
			
		||||
                    ->invoices()
 | 
			
		||||
                    ->whereIsPublic(true)
 | 
			
		||||
                    ->where('invoices.balance', '>', 0)
 | 
			
		||||
                    ->with('client', 'invoice_status')
 | 
			
		||||
                    ->orderBy('invoice_number')->get();
 | 
			
		||||
 | 
			
		||||
@ -33,9 +33,8 @@ class CreatePaymentAPIRequest extends PaymentRequest
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $invoice = Invoice::scope($this->invoice_id)
 | 
			
		||||
        $this->invoice = $invoice = Invoice::scope($this->invoice_id)
 | 
			
		||||
            ->invoices()
 | 
			
		||||
            ->whereIsPublic(true)
 | 
			
		||||
            ->firstOrFail();
 | 
			
		||||
 | 
			
		||||
        $this->merge([
 | 
			
		||||
 | 
			
		||||
@ -426,6 +426,25 @@ class Invoice extends EntityModel implements BalanceAffecting
 | 
			
		||||
        return $this->isType(INVOICE_TYPE_STANDARD) && ! $this->is_recurring;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function markSentIfUnsent()
 | 
			
		||||
    {
 | 
			
		||||
        if ( ! $this->isSent()) {
 | 
			
		||||
            $this->markSent();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function markSent()
 | 
			
		||||
    {
 | 
			
		||||
        if ( ! $this->isSent()) {
 | 
			
		||||
            $this->invoice_status_id = INVOICE_STATUS_SENT;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->is_public = true;
 | 
			
		||||
        $this->save();
 | 
			
		||||
 | 
			
		||||
        $this->markInvitationsSent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param bool $notify
 | 
			
		||||
     */
 | 
			
		||||
@ -462,7 +481,7 @@ class Invoice extends EntityModel implements BalanceAffecting
 | 
			
		||||
     */
 | 
			
		||||
    public function markInvitationSent($invitation, $messageId = false, $notify = true, $notes = false)
 | 
			
		||||
    {
 | 
			
		||||
        if (!$this->isSent()) {
 | 
			
		||||
        if ( ! $this->isSent()) {
 | 
			
		||||
            $this->invoice_status_id = INVOICE_STATUS_SENT;
 | 
			
		||||
            $this->save();
 | 
			
		||||
        }
 | 
			
		||||
@ -667,7 +686,7 @@ class Invoice extends EntityModel implements BalanceAffecting
 | 
			
		||||
     */
 | 
			
		||||
    public function isSent()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->invoice_status_id >= INVOICE_STATUS_SENT && $this->is_public;
 | 
			
		||||
        return $this->invoice_status_id >= INVOICE_STATUS_SENT && $this->getOriginal('is_public');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
use stdClass;
 | 
			
		||||
use Utils;
 | 
			
		||||
use DropdownButton;
 | 
			
		||||
use App\Libraries\Skype\InvoiceCard;
 | 
			
		||||
 | 
			
		||||
class InvoicePresenter extends EntityPresenter {
 | 
			
		||||
@ -162,4 +163,50 @@ class InvoicePresenter extends EntityPresenter {
 | 
			
		||||
 | 
			
		||||
        return [$data];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function moreActions()
 | 
			
		||||
    {
 | 
			
		||||
        $invoice = $this->entity;
 | 
			
		||||
        $entityType = $invoice->getEntityType();
 | 
			
		||||
 | 
			
		||||
        $actions = [
 | 
			
		||||
            ['url' => 'javascript:onCloneClick()', 'label' => trans("texts.clone_{$entityType}")],
 | 
			
		||||
            ['url' => url("{$entityType}s/{$entityType}_history/{$invoice->public_id}"), 'label' => trans('texts.view_history')],
 | 
			
		||||
            DropdownButton::DIVIDER
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        if ($entityType == ENTITY_QUOTE) {
 | 
			
		||||
            if ($invoice->quote_invoice_id) {
 | 
			
		||||
                $actions[] = ['url' => url("invoices/{$invoice->quote_invoice_id}/edit"), 'label' => trans('texts.view_invoice')];
 | 
			
		||||
            } else {
 | 
			
		||||
                $actions[] = ['url' => 'javascript:onConvertClick()', 'label' => trans('texts.convert_to_invoice')];
 | 
			
		||||
            }
 | 
			
		||||
        } elseif ($entityType == ENTITY_INVOICE) {
 | 
			
		||||
            if ($invoice->quote_id) {
 | 
			
		||||
                $actions[] = ['url' => url("quotes/{$invoice->quote_id}/edit"), 'label' => trans('texts.view_quote')];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!$invoice->is_recurring && $invoice->balance > 0) {
 | 
			
		||||
                $actions[] = ['url' => 'javascript:submitBulkAction("markPaid")', 'label' => trans('texts.mark_paid')];
 | 
			
		||||
                $actions[] = ['url' => 'javascript:onPaymentClick()', 'label' => trans('texts.enter_payment')];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach ($invoice->payments as $payment) {
 | 
			
		||||
                $label = trans('texts.view_payment');
 | 
			
		||||
                if (count($invoice->payments) > 1) {
 | 
			
		||||
                    $label .= ' - ' . $invoice->account->formatMoney($payment->amount, $invoice->client);
 | 
			
		||||
                }
 | 
			
		||||
                $actions[] = ['url' => $payment->present()->url, 'label' => $label];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (count($actions) > 3) {
 | 
			
		||||
            $actions[] = DropdownButton::DIVIDER;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $actions[] = ['url' => 'javascript:onArchiveClick()', 'label' => trans("texts.archive_{$entityType}")];
 | 
			
		||||
        $actions[] = ['url' => 'javascript:onDeleteClick()', 'label' => trans("texts.delete_{$entityType}")];
 | 
			
		||||
 | 
			
		||||
        return $actions;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -761,14 +761,7 @@ class InvoiceRepository extends BaseRepository
 | 
			
		||||
     */
 | 
			
		||||
    public function markSent(Invoice $invoice)
 | 
			
		||||
    {
 | 
			
		||||
        if ( ! $invoice->isSent()) {
 | 
			
		||||
            $invoice->invoice_status_id = INVOICE_STATUS_SENT;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $invoice->is_public = true;
 | 
			
		||||
        $invoice->save();
 | 
			
		||||
 | 
			
		||||
        $invoice->markInvitationsSent();
 | 
			
		||||
        $invoice->markSent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -199,7 +199,7 @@ class AppServiceProvider extends ServiceProvider
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
		Validator::extend('valid_subdomain', function($attribute, $value, $parameters) {
 | 
			
		||||
			return ! in_array($value, ['www', 'app','mail', 'admin', 'blog', 'user', 'contact', 'payment', 'payments', 'billing', 'invoice', 'business', 'owner', 'info', 'ninja', 'docs', 'doc', 'documents']);
 | 
			
		||||
			return ! in_array($value, ['www', 'app', 'mail', 'admin', 'blog', 'user', 'contact', 'payment', 'payments', 'billing', 'invoice', 'business', 'owner', 'info', 'ninja', 'docs', 'doc', 'documents', 'download']);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -564,7 +564,7 @@
 | 
			
		||||
                    @if (!$invoice->trashed())
 | 
			
		||||
                        @if ($invoice->id)
 | 
			
		||||
                            {!! DropdownButton::normal(trans('texts.more_actions'))
 | 
			
		||||
                                  ->withContents($actions)
 | 
			
		||||
                                  ->withContents($invoice->present()->moreActions())
 | 
			
		||||
                                  ->dropup() !!}
 | 
			
		||||
                        @elseif ( ! $invoice->isQuote() && Request::is('*/clone'))
 | 
			
		||||
                            {!! Button::normal(trans($invoice->is_recurring ? 'texts.disable_recurring' : 'texts.enable_recurring'))->withAttributes(['id' => 'recurrButton', 'onclick' => 'onRecurrClick()'])->appendIcon(Icon::create('repeat')) !!}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user