mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-07 15:54:31 -04:00
Support paying draft invoices
This commit is contained in:
parent
2da91729b3
commit
eebe61b4d0
@ -9,7 +9,6 @@ use Cache;
|
|||||||
use Redirect;
|
use Redirect;
|
||||||
use DB;
|
use DB;
|
||||||
use URL;
|
use URL;
|
||||||
use DropdownButton;
|
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
@ -123,46 +122,6 @@ class InvoiceController extends BaseController
|
|||||||
'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS),
|
'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;
|
$lastSent = ($invoice->is_recurring && $invoice->last_sent_date) ? $invoice->recurring_invoices->last() : null;
|
||||||
|
|
||||||
if(!Auth::user()->hasPermission('view_all')){
|
if(!Auth::user()->hasPermission('view_all')){
|
||||||
@ -180,7 +139,6 @@ class InvoiceController extends BaseController
|
|||||||
'title' => trans("texts.edit_{$entityType}"),
|
'title' => trans("texts.edit_{$entityType}"),
|
||||||
'client' => $invoice->client,
|
'client' => $invoice->client,
|
||||||
'isRecurring' => $invoice->is_recurring,
|
'isRecurring' => $invoice->is_recurring,
|
||||||
'actions' => $actions,
|
|
||||||
'lastSent' => $lastSent];
|
'lastSent' => $lastSent];
|
||||||
$data = array_merge($data, self::getViewModel($invoice));
|
$data = array_merge($data, self::getViewModel($invoice));
|
||||||
|
|
||||||
|
@ -108,6 +108,9 @@ class PaymentApiController extends BaseAPIController
|
|||||||
*/
|
*/
|
||||||
public function store(CreatePaymentAPIRequest $request)
|
public function store(CreatePaymentAPIRequest $request)
|
||||||
{
|
{
|
||||||
|
// check payment has been marked sent
|
||||||
|
$request->invoice->markSentIfUnsent();
|
||||||
|
|
||||||
$payment = $this->paymentRepo->save($request->input());
|
$payment = $this->paymentRepo->save($request->input());
|
||||||
|
|
||||||
if (Input::get('email_receipt')) {
|
if (Input::get('email_receipt')) {
|
||||||
@ -142,7 +145,7 @@ class PaymentApiController extends BaseAPIController
|
|||||||
public function destroy(UpdatePaymentRequest $request)
|
public function destroy(UpdatePaymentRequest $request)
|
||||||
{
|
{
|
||||||
$payment = $request->entity();
|
$payment = $request->entity();
|
||||||
|
|
||||||
$this->clientRepo->delete($payment);
|
$this->clientRepo->delete($payment);
|
||||||
|
|
||||||
return $this->itemResponse($payment);
|
return $this->itemResponse($payment);
|
||||||
|
@ -85,7 +85,6 @@ class PaymentController extends BaseController
|
|||||||
{
|
{
|
||||||
$invoices = Invoice::scope()
|
$invoices = Invoice::scope()
|
||||||
->invoices()
|
->invoices()
|
||||||
->whereIsPublic(true)
|
|
||||||
->where('invoices.balance', '>', 0)
|
->where('invoices.balance', '>', 0)
|
||||||
->with('client', 'invoice_status')
|
->with('client', 'invoice_status')
|
||||||
->orderBy('invoice_number')->get();
|
->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()
|
->invoices()
|
||||||
->whereIsPublic(true)
|
|
||||||
->firstOrFail();
|
->firstOrFail();
|
||||||
|
|
||||||
$this->merge([
|
$this->merge([
|
||||||
|
@ -426,6 +426,25 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
return $this->isType(INVOICE_TYPE_STANDARD) && ! $this->is_recurring;
|
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
|
* @param bool $notify
|
||||||
*/
|
*/
|
||||||
@ -462,7 +481,7 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
*/
|
*/
|
||||||
public function markInvitationSent($invitation, $messageId = false, $notify = true, $notes = false)
|
public function markInvitationSent($invitation, $messageId = false, $notify = true, $notes = false)
|
||||||
{
|
{
|
||||||
if (!$this->isSent()) {
|
if ( ! $this->isSent()) {
|
||||||
$this->invoice_status_id = INVOICE_STATUS_SENT;
|
$this->invoice_status_id = INVOICE_STATUS_SENT;
|
||||||
$this->save();
|
$this->save();
|
||||||
}
|
}
|
||||||
@ -667,7 +686,7 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
*/
|
*/
|
||||||
public function isSent()
|
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 stdClass;
|
||||||
use Utils;
|
use Utils;
|
||||||
|
use DropdownButton;
|
||||||
use App\Libraries\Skype\InvoiceCard;
|
use App\Libraries\Skype\InvoiceCard;
|
||||||
|
|
||||||
class InvoicePresenter extends EntityPresenter {
|
class InvoicePresenter extends EntityPresenter {
|
||||||
@ -162,4 +163,50 @@ class InvoicePresenter extends EntityPresenter {
|
|||||||
|
|
||||||
return [$data];
|
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)
|
public function markSent(Invoice $invoice)
|
||||||
{
|
{
|
||||||
if ( ! $invoice->isSent()) {
|
$invoice->markSent();
|
||||||
$invoice->invoice_status_id = INVOICE_STATUS_SENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice->is_public = true;
|
|
||||||
$invoice->save();
|
|
||||||
|
|
||||||
$invoice->markInvitationsSent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -199,7 +199,7 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
});
|
});
|
||||||
|
|
||||||
Validator::extend('valid_subdomain', function($attribute, $value, $parameters) {
|
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->trashed())
|
||||||
@if ($invoice->id)
|
@if ($invoice->id)
|
||||||
{!! DropdownButton::normal(trans('texts.more_actions'))
|
{!! DropdownButton::normal(trans('texts.more_actions'))
|
||||||
->withContents($actions)
|
->withContents($invoice->present()->moreActions())
|
||||||
->dropup() !!}
|
->dropup() !!}
|
||||||
@elseif ( ! $invoice->isQuote() && Request::is('*/clone'))
|
@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')) !!}
|
{!! 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