2017-01-30 20:40:43 +01:00
< ? php
2013-12-25 22:34:42 +01:00
2017-01-30 20:40:43 +01:00
namespace App\Ninja\Repositories ;
2017-04-09 08:41:02 +02:00
use App\Events\QuoteItemsWereCreated ;
use App\Events\QuoteItemsWereUpdated ;
use App\Events\InvoiceItemsWereCreated ;
use App\Events\InvoiceItemsWereUpdated ;
2017-01-30 20:40:43 +01:00
use App\Jobs\SendInvoiceEmail ;
2016-07-03 18:11:58 +02:00
use App\Models\Account ;
2017-01-30 13:35:04 +01:00
use App\Models\Client ;
2017-01-30 20:40:43 +01:00
use App\Models\Document ;
use App\Models\Expense ;
use App\Models\Invitation ;
2015-03-31 11:38:24 +02:00
use App\Models\Invoice ;
use App\Models\InvoiceItem ;
use App\Models\Product ;
2015-05-27 18:52:10 +02:00
use App\Models\Task ;
2017-03-17 11:47:17 +01:00
use App\Models\GatewayType ;
2015-09-10 19:50:09 +02:00
use App\Services\PaymentService ;
2017-01-30 20:40:43 +01:00
use Auth ;
use DB ;
use Utils ;
2013-12-25 22:34:42 +01:00
2015-10-28 20:22:07 +01:00
class InvoiceRepository extends BaseRepository
2013-12-25 22:34:42 +01:00
{
2016-03-24 20:13:54 +01:00
protected $documentRepo ;
2015-10-28 20:22:07 +01:00
public function getClassName ()
{
return 'App\Models\Invoice' ;
}
2016-12-14 20:47:22 +01:00
public function __construct ( PaymentService $paymentService , DocumentRepository $documentRepo , PaymentRepository $paymentRepo )
2015-09-10 19:50:09 +02:00
{
2016-03-24 20:13:54 +01:00
$this -> documentRepo = $documentRepo ;
2015-09-10 19:50:09 +02:00
$this -> paymentService = $paymentService ;
2016-12-14 20:47:22 +01:00
$this -> paymentRepo = $paymentRepo ;
2015-09-10 19:50:09 +02:00
}
2015-11-18 15:40:50 +01:00
public function all ()
{
return Invoice :: scope ()
2016-05-26 16:56:54 +02:00
-> invoiceType ( INVOICE_TYPE_STANDARD )
2015-11-18 15:40:50 +01:00
-> with ( 'user' , 'client.contacts' , 'invoice_status' )
-> withTrashed ()
-> where ( 'is_recurring' , '=' , false )
-> get ();
}
2015-01-11 12:56:58 +01:00
public function getInvoices ( $accountId , $clientPublicId = false , $entityType = ENTITY_INVOICE , $filter = false )
{
2015-12-07 14:34:55 +01:00
$query = DB :: table ( 'invoices' )
-> join ( 'accounts' , 'accounts.id' , '=' , 'invoices.account_id' )
2015-01-11 12:56:58 +01:00
-> join ( 'clients' , 'clients.id' , '=' , 'invoices.client_id' )
-> join ( 'invoice_statuses' , 'invoice_statuses.id' , '=' , 'invoices.invoice_status_id' )
-> join ( 'contacts' , 'contacts.client_id' , '=' , 'clients.id' )
2014-05-20 23:40:09 +02:00
-> where ( 'invoices.account_id' , '=' , $accountId )
2014-06-02 18:21:47 +02:00
-> where ( 'contacts.deleted_at' , '=' , null )
2015-01-11 12:56:58 +01:00
-> where ( 'invoices.is_recurring' , '=' , false )
-> where ( 'contacts.is_primary' , '=' , true )
2016-10-20 17:14:54 +02:00
//->whereRaw('(clients.name != "" or contacts.first_name != "" or contacts.last_name != "" or contacts.email != "")') // filter out buy now invoices
2015-12-07 14:34:55 +01:00
-> select (
DB :: raw ( 'COALESCE(clients.currency_id, accounts.currency_id) currency_id' ),
DB :: raw ( 'COALESCE(clients.country_id, accounts.country_id) country_id' ),
'clients.public_id as client_public_id' ,
2016-03-16 03:07:11 +01:00
'clients.user_id as client_user_id' ,
2015-12-07 14:34:55 +01:00
'invoice_number' ,
2016-11-24 10:22:37 +01:00
'invoice_number as quote_number' ,
2015-12-07 14:34:55 +01:00
'invoice_status_id' ,
2016-04-27 10:49:54 +02:00
DB :: raw ( " COALESCE(NULLIF(clients.name,''), NULLIF(CONCAT(contacts.first_name, ' ', contacts.last_name),''), NULLIF(contacts.email,'')) client_name " ),
2015-12-07 14:34:55 +01:00
'invoices.public_id' ,
'invoices.amount' ,
'invoices.balance' ,
2017-03-28 11:40:53 +02:00
'invoices.invoice_date' ,
'invoices.due_date as due_date_sql' ,
2017-10-26 09:56:59 +02:00
'invoices.partial_due_date' ,
2017-03-28 11:40:53 +02:00
DB :: raw ( " CONCAT(invoices.invoice_date, invoices.created_at) as date " ),
2017-10-26 09:56:59 +02:00
DB :: raw ( " CONCAT(COALESCE(invoices.partial_due_date, invoices.due_date), invoices.created_at) as due_date " ),
DB :: raw ( " CONCAT(COALESCE(invoices.partial_due_date, invoices.due_date), invoices.created_at) as valid_until " ),
2016-11-24 10:22:37 +01:00
'invoice_statuses.name as status' ,
2015-12-07 14:34:55 +01:00
'invoice_statuses.name as invoice_status_name' ,
'contacts.first_name' ,
'contacts.last_name' ,
'contacts.email' ,
'invoices.quote_id' ,
'invoices.quote_invoice_id' ,
'invoices.deleted_at' ,
'invoices.is_deleted' ,
2016-03-16 00:08:00 +01:00
'invoices.partial' ,
2016-12-04 22:26:38 +01:00
'invoices.user_id' ,
2017-02-07 10:58:00 +01:00
'invoices.is_public' ,
2017-10-14 19:55:37 +02:00
'invoices.is_recurring' ,
'invoices.private_notes'
2015-12-07 14:34:55 +01:00
);
2015-01-11 12:56:58 +01:00
2016-11-18 14:31:43 +01:00
$this -> applyFilters ( $query , $entityType , ENTITY_INVOICE );
2016-11-20 15:08:36 +01:00
if ( $statuses = session ( 'entity_status_filter:' . $entityType )) {
$statuses = explode ( ',' , $statuses );
2016-11-18 14:31:43 +01:00
$query -> where ( function ( $query ) use ( $statuses ) {
foreach ( $statuses as $status ) {
if ( in_array ( $status , \App\Models\EntityModel :: $statuses )) {
continue ;
}
$query -> orWhere ( 'invoice_status_id' , '=' , $status );
}
2017-02-07 15:26:23 +01:00
if ( in_array ( INVOICE_STATUS_UNPAID , $statuses )) {
$query -> orWhere ( function ( $query ) use ( $statuses ) {
$query -> where ( 'invoices.balance' , '>' , 0 )
-> where ( 'invoices.is_public' , '=' , true );
});
}
2016-11-18 14:31:43 +01:00
if ( in_array ( INVOICE_STATUS_OVERDUE , $statuses )) {
$query -> orWhere ( function ( $query ) use ( $statuses ) {
$query -> where ( 'invoices.balance' , '>' , 0 )
2017-02-07 11:49:33 +01:00
-> where ( 'invoices.due_date' , '<' , date ( 'Y-m-d' ))
-> where ( 'invoices.is_public' , '=' , true );
2016-11-18 14:31:43 +01:00
});
}
});
2015-01-11 12:56:58 +01:00
}
if ( $clientPublicId ) {
$query -> where ( 'clients.public_id' , '=' , $clientPublicId );
2016-11-27 13:20:58 +01:00
} else {
$query -> whereNull ( 'clients.deleted_at' );
2015-01-11 12:56:58 +01:00
}
if ( $filter ) {
$query -> where ( function ( $query ) use ( $filter ) {
$query -> where ( 'clients.name' , 'like' , '%' . $filter . '%' )
-> orWhere ( 'invoices.invoice_number' , 'like' , '%' . $filter . '%' )
2016-11-27 10:46:32 +01:00
-> orWhere ( 'contacts.first_name' , 'like' , '%' . $filter . '%' )
-> orWhere ( 'contacts.last_name' , 'like' , '%' . $filter . '%' )
-> orWhere ( 'contacts.email' , 'like' , '%' . $filter . '%' );
2013-12-25 22:34:42 +01:00
});
2015-01-11 12:56:58 +01:00
}
return $query ;
}
public function getRecurringInvoices ( $accountId , $clientPublicId = false , $filter = false )
{
2015-12-07 14:34:55 +01:00
$query = DB :: table ( 'invoices' )
-> join ( 'accounts' , 'accounts.id' , '=' , 'invoices.account_id' )
2015-01-11 12:56:58 +01:00
-> join ( 'clients' , 'clients.id' , '=' , 'invoices.client_id' )
2017-03-09 14:08:18 +01:00
-> join ( 'invoice_statuses' , 'invoice_statuses.id' , '=' , 'invoices.invoice_status_id' )
2017-06-28 16:39:32 +02:00
-> leftJoin ( 'frequencies' , 'frequencies.id' , '=' , 'invoices.frequency_id' )
2015-01-11 12:56:58 +01:00
-> join ( 'contacts' , 'contacts.client_id' , '=' , 'clients.id' )
-> where ( 'invoices.account_id' , '=' , $accountId )
2016-05-26 16:56:54 +02:00
-> where ( 'invoices.invoice_type_id' , '=' , INVOICE_TYPE_STANDARD )
2015-01-11 12:56:58 +01:00
-> where ( 'contacts.deleted_at' , '=' , null )
-> where ( 'invoices.is_recurring' , '=' , true )
-> where ( 'contacts.is_primary' , '=' , true )
2015-12-07 14:34:55 +01:00
-> select (
DB :: raw ( 'COALESCE(clients.currency_id, accounts.currency_id) currency_id' ),
DB :: raw ( 'COALESCE(clients.country_id, accounts.country_id) country_id' ),
'clients.public_id as client_public_id' ,
2016-04-27 10:49:54 +02:00
DB :: raw ( " COALESCE(NULLIF(clients.name,''), NULLIF(CONCAT(contacts.first_name, ' ', contacts.last_name),''), NULLIF(contacts.email,'')) client_name " ),
2015-12-07 14:34:55 +01:00
'invoices.public_id' ,
'invoices.amount' ,
'frequencies.name as frequency' ,
2017-03-28 11:40:53 +02:00
'invoices.start_date as start_date_sql' ,
'invoices.end_date as end_date_sql' ,
'invoices.last_sent_date as last_sent_date_sql' ,
DB :: raw ( " CONCAT(invoices.start_date, invoices.created_at) as start_date " ),
DB :: raw ( " CONCAT(invoices.end_date, invoices.created_at) as end_date " ),
DB :: raw ( " CONCAT(invoices.last_sent_date, invoices.created_at) as last_sent " ),
2015-12-07 14:34:55 +01:00
'contacts.first_name' ,
'contacts.last_name' ,
'contacts.email' ,
'invoices.deleted_at' ,
2016-05-06 20:26:37 +02:00
'invoices.is_deleted' ,
2017-03-09 14:08:18 +01:00
'invoices.user_id' ,
'invoice_statuses.name as invoice_status_name' ,
2017-07-02 17:54:28 +02:00
'invoice_statuses.name as status' ,
2017-03-09 14:08:18 +01:00
'invoices.invoice_status_id' ,
'invoices.balance' ,
'invoices.due_date' ,
2017-03-28 11:40:53 +02:00
'invoices.due_date as due_date_sql' ,
2017-03-09 14:08:18 +01:00
'invoices.is_recurring' ,
2017-05-16 20:37:26 +02:00
'invoices.quote_invoice_id' ,
'invoices.private_notes'
2015-12-07 14:34:55 +01:00
);
2015-01-11 12:56:58 +01:00
if ( $clientPublicId ) {
$query -> where ( 'clients.public_id' , '=' , $clientPublicId );
2016-11-27 13:20:58 +01:00
} else {
$query -> whereNull ( 'clients.deleted_at' );
2015-01-11 12:56:58 +01:00
}
2016-11-18 14:31:43 +01:00
$this -> applyFilters ( $query , ENTITY_RECURRING_INVOICE , ENTITY_INVOICE );
2015-01-11 12:56:58 +01:00
if ( $filter ) {
$query -> where ( function ( $query ) use ( $filter ) {
$query -> where ( 'clients.name' , 'like' , '%' . $filter . '%' )
2016-12-19 10:48:33 +01:00
-> orWhere ( 'invoices.invoice_number' , 'like' , '%' . $filter . '%' )
-> orWhere ( 'contacts.first_name' , 'like' , '%' . $filter . '%' )
-> orWhere ( 'contacts.last_name' , 'like' , '%' . $filter . '%' )
-> orWhere ( 'contacts.email' , 'like' , '%' . $filter . '%' );
2013-12-25 22:34:42 +01:00
});
2015-01-11 12:56:58 +01:00
}
2013-12-25 22:34:42 +01:00
2015-01-11 12:56:58 +01:00
return $query ;
}
2013-12-25 22:34:42 +01:00
2016-05-06 19:26:37 +02:00
public function getClientRecurringDatatable ( $contactId )
2015-01-11 12:56:58 +01:00
{
2015-12-07 14:34:55 +01:00
$query = DB :: table ( 'invitations' )
-> join ( 'accounts' , 'accounts.id' , '=' , 'invitations.account_id' )
2015-01-11 12:56:58 +01:00
-> join ( 'invoices' , 'invoices.id' , '=' , 'invitations.invoice_id' )
-> join ( 'clients' , 'clients.id' , '=' , 'invoices.client_id' )
2016-05-06 19:26:37 +02:00
-> join ( 'frequencies' , 'frequencies.id' , '=' , 'invoices.frequency_id' )
2014-11-12 22:09:42 +01:00
-> where ( 'invitations.contact_id' , '=' , $contactId )
-> where ( 'invitations.deleted_at' , '=' , null )
2016-05-26 16:56:54 +02:00
-> where ( 'invoices.invoice_type_id' , '=' , INVOICE_TYPE_STANDARD )
2014-11-12 22:09:42 +01:00
-> where ( 'invoices.is_deleted' , '=' , false )
-> where ( 'clients.deleted_at' , '=' , null )
2016-05-06 19:26:37 +02:00
-> where ( 'invoices.is_recurring' , '=' , true )
2016-12-05 09:11:33 +01:00
-> where ( 'invoices.is_public' , '=' , true )
2017-07-04 22:49:00 +02:00
-> where ( 'invoices.deleted_at' , '=' , null )
2016-05-06 19:26:37 +02:00
//->where('invoices.start_date', '>=', date('Y-m-d H:i:s'))
2015-12-07 14:34:55 +01:00
-> select (
2016-05-06 19:26:37 +02:00
DB :: raw ( 'COALESCE(clients.currency_id, accounts.currency_id) currency_id' ),
DB :: raw ( 'COALESCE(clients.country_id, accounts.country_id) country_id' ),
'invitations.invitation_key' ,
'invoices.invoice_number' ,
'invoices.due_date' ,
'clients.public_id as client_public_id' ,
'clients.name as client_name' ,
'invoices.public_id' ,
'invoices.amount' ,
'invoices.start_date' ,
'invoices.end_date' ,
2017-04-03 21:06:09 +02:00
'invoices.auto_bill' ,
2016-05-09 22:29:02 +02:00
'invoices.client_enable_auto_bill' ,
2016-05-06 19:26:37 +02:00
'frequencies.name as frequency'
);
$table = \Datatable :: query ( $query )
2017-01-30 17:05:31 +01:00
-> addColumn ( 'frequency' , function ( $model ) {
2018-04-11 22:22:08 +02:00
$frequency = strtolower ( $model -> frequency );
$frequency = preg_replace ( '/\s/' , '_' , $frequency );
return trans ( 'texts.freq_' . $frequency );
2017-01-30 17:05:31 +01:00
})
-> addColumn ( 'start_date' , function ( $model ) {
return Utils :: fromSqlDate ( $model -> start_date );
})
-> addColumn ( 'end_date' , function ( $model ) {
return Utils :: fromSqlDate ( $model -> end_date );
})
-> addColumn ( 'amount' , function ( $model ) {
return Utils :: formatMoney ( $model -> amount , $model -> currency_id , $model -> country_id );
})
2016-05-09 22:29:02 +02:00
-> addColumn ( 'client_enable_auto_bill' , function ( $model ) {
2017-04-03 21:06:09 +02:00
if ( $model -> auto_bill == AUTO_BILL_OFF ) {
return trans ( 'texts.disabled' );
} elseif ( $model -> auto_bill == AUTO_BILL_ALWAYS ) {
return trans ( 'texts.enabled' );
} elseif ( $model -> client_enable_auto_bill ) {
2016-06-30 20:05:02 +02:00
return trans ( 'texts.enabled' ) . ' - <a href="javascript:setAutoBill(' . $model -> public_id . ',false)">' . trans ( 'texts.disable' ) . '</a>' ;
2016-05-06 19:26:37 +02:00
} else {
2016-06-30 20:05:02 +02:00
return trans ( 'texts.disabled' ) . ' - <a href="javascript:setAutoBill(' . $model -> public_id . ',true)">' . trans ( 'texts.enable' ) . '</a>' ;
2016-05-06 19:26:37 +02:00
}
});
return $table -> make ();
}
public function getClientDatatable ( $contactId , $entityType , $search )
{
$query = DB :: table ( 'invitations' )
2015-12-07 14:34:55 +01:00
-> join ( 'accounts' , 'accounts.id' , '=' , 'invitations.account_id' )
2015-01-11 12:56:58 +01:00
-> join ( 'invoices' , 'invoices.id' , '=' , 'invitations.invoice_id' )
-> join ( 'clients' , 'clients.id' , '=' , 'invoices.client_id' )
2016-05-01 10:43:10 +02:00
-> join ( 'contacts' , 'contacts.client_id' , '=' , 'clients.id' )
2014-11-12 22:09:42 +01:00
-> where ( 'invitations.contact_id' , '=' , $contactId )
-> where ( 'invitations.deleted_at' , '=' , null )
2016-05-26 16:56:54 +02:00
-> where ( 'invoices.invoice_type_id' , '=' , $entityType == ENTITY_QUOTE ? INVOICE_TYPE_QUOTE : INVOICE_TYPE_STANDARD )
2014-11-12 22:09:42 +01:00
-> where ( 'invoices.is_deleted' , '=' , false )
-> where ( 'clients.deleted_at' , '=' , null )
2016-05-01 10:43:10 +02:00
-> where ( 'contacts.deleted_at' , '=' , null )
-> where ( 'contacts.is_primary' , '=' , true )
2014-11-12 22:09:42 +01:00
-> where ( 'invoices.is_recurring' , '=' , false )
2016-12-04 22:26:38 +01:00
-> where ( 'invoices.is_public' , '=' , true )
2016-12-29 13:30:23 +01:00
// Only show paid invoices for ninja accounts
2017-06-13 15:14:44 +02:00
-> whereRaw ( sprintf ( " ((accounts.account_key != '%s' and accounts.account_key not like '%s%%') or invoices.invoice_status_id = %d) " , env ( 'NINJA_LICENSE_ACCOUNT_KEY' ), substr ( NINJA_ACCOUNT_KEY , 0 , 30 ), INVOICE_STATUS_PAID ))
2015-12-07 14:34:55 +01:00
-> select (
DB :: raw ( 'COALESCE(clients.currency_id, accounts.currency_id) currency_id' ),
DB :: raw ( 'COALESCE(clients.country_id, accounts.country_id) country_id' ),
'invitations.invitation_key' ,
'invoices.invoice_number' ,
'invoices.invoice_date' ,
'invoices.balance as balance' ,
'invoices.due_date' ,
2017-07-27 18:37:09 +02:00
'invoices.invoice_status_id' ,
'invoices.due_date' ,
'invoices.quote_invoice_id' ,
2015-12-07 14:34:55 +01:00
'clients.public_id as client_public_id' ,
2016-04-27 10:49:54 +02:00
DB :: raw ( " COALESCE(NULLIF(clients.name,''), NULLIF(CONCAT(contacts.first_name, ' ', contacts.last_name),''), NULLIF(contacts.email,'')) client_name " ),
2015-12-07 14:34:55 +01:00
'invoices.public_id' ,
'invoices.amount' ,
'invoices.start_date' ,
'invoices.end_date' ,
'invoices.partial'
);
2014-11-12 22:09:42 +01:00
2015-01-11 12:56:58 +01:00
$table = \Datatable :: query ( $query )
2017-01-30 17:05:31 +01:00
-> addColumn ( 'invoice_number' , function ( $model ) use ( $entityType ) {
return link_to ( '/view/' . $model -> invitation_key , $model -> invoice_number ) -> toHtml ();
})
-> addColumn ( 'invoice_date' , function ( $model ) {
return Utils :: fromSqlDate ( $model -> invoice_date );
})
-> addColumn ( 'amount' , function ( $model ) {
return Utils :: formatMoney ( $model -> amount , $model -> currency_id , $model -> country_id );
});
2014-11-12 22:09:42 +01:00
2015-01-11 12:56:58 +01:00
if ( $entityType == ENTITY_INVOICE ) {
2015-04-16 21:57:12 +02:00
$table -> addColumn ( 'balance' , function ( $model ) {
return $model -> partial > 0 ?
2015-12-07 14:34:55 +01:00
trans ( 'texts.partial_remaining' , [
2016-01-10 11:25:05 +01:00
'partial' => Utils :: formatMoney ( $model -> partial , $model -> currency_id , $model -> country_id ),
2017-01-30 20:40:43 +01:00
'balance' => Utils :: formatMoney ( $model -> balance , $model -> currency_id , $model -> country_id ),
2015-12-07 14:34:55 +01:00
]) :
Utils :: formatMoney ( $model -> balance , $model -> currency_id , $model -> country_id );
2015-04-16 21:57:12 +02:00
});
2015-01-11 12:56:58 +01:00
}
2017-01-30 17:05:31 +01:00
return $table -> addColumn ( 'due_date' , function ( $model ) {
return Utils :: fromSqlDate ( $model -> due_date );
})
2017-08-11 11:31:38 +02:00
-> addColumn ( 'invoice_status_id' , function ( $model ) use ( $entityType ) {
2017-07-27 18:37:09 +02:00
if ( $model -> invoice_status_id == INVOICE_STATUS_PAID ) {
$label = trans ( 'texts.status_paid' );
$class = 'success' ;
} elseif ( $model -> invoice_status_id == INVOICE_STATUS_PARTIAL ) {
$label = trans ( 'texts.status_partial' );
$class = 'info' ;
2017-12-13 08:12:29 +01:00
} elseif ( $entityType == ENTITY_QUOTE && ( $model -> invoice_status_id >= INVOICE_STATUS_APPROVED || $model -> quote_invoice_id )) {
$label = trans ( 'texts.status_approved' );
$class = 'success' ;
2017-07-27 18:37:09 +02:00
} elseif ( Invoice :: calcIsOverdue ( $model -> balance , $model -> due_date )) {
$class = 'danger' ;
if ( $entityType == ENTITY_INVOICE ) {
2017-10-17 20:21:13 +02:00
$label = trans ( 'texts.past_due' );
2017-07-27 18:37:09 +02:00
} else {
$label = trans ( 'texts.expired' );
}
} else {
$class = 'default' ;
if ( $entityType == ENTITY_INVOICE ) {
$label = trans ( 'texts.unpaid' );
} else {
$label = trans ( 'texts.pending' );
}
}
return " <h4><div class= \" label label- { $class } \" > $label </div></h4> " ;
})
-> make ();
2015-01-11 12:56:58 +01:00
}
2014-11-12 22:09:42 +01:00
2016-07-03 18:11:58 +02:00
/**
2017-01-30 20:40:43 +01:00
* @ param array $data
2016-07-03 18:11:58 +02:00
* @ param Invoice | null $invoice
2017-01-30 20:40:43 +01:00
*
2016-07-03 18:11:58 +02:00
* @ return Invoice | mixed
*/
public function save ( array $data , Invoice $invoice = null )
2014-05-20 23:40:09 +02:00
{
2016-07-03 18:11:58 +02:00
/** @var Account $account */
2017-03-17 15:41:19 +01:00
$account = $invoice ? $invoice -> account : \Auth :: user () -> account ;
2015-10-28 20:22:07 +01:00
$publicId = isset ( $data [ 'public_id' ]) ? $data [ 'public_id' ] : false ;
2015-12-07 14:34:55 +01:00
2018-04-24 15:20:38 +02:00
if ( Utils :: isNinjaProd () && ! Utils :: isReseller ()) {
$copy = json_decode ( json_encode ( $data ), true );
$copy [ 'data' ] = false ;
2018-04-29 08:38:30 +02:00
$logMessage = date ( 'r' ) . ' account_id: ' . $account -> id . ' ' . json_encode ( $copy ) . " \n \n " ;
2018-04-24 15:20:38 +02:00
@ file_put_contents ( storage_path ( 'logs/invoice-repo.log' ), $logMessage , FILE_APPEND );
}
2018-06-19 22:19:40 +02:00
$isNew = ! $publicId || intval ( $publicId ) < 0 ;
2015-10-25 08:13:06 +01:00
2016-05-02 19:42:13 +02:00
if ( $invoice ) {
// do nothing
2016-08-09 16:14:26 +02:00
$entityType = $invoice -> getEntityType ();
2016-05-02 19:42:13 +02:00
} elseif ( $isNew ) {
2015-10-28 20:22:07 +01:00
$entityType = ENTITY_INVOICE ;
2015-11-29 11:58:40 +01:00
if ( isset ( $data [ 'is_recurring' ]) && filter_var ( $data [ 'is_recurring' ], FILTER_VALIDATE_BOOLEAN )) {
2015-10-25 08:13:06 +01:00
$entityType = ENTITY_RECURRING_INVOICE ;
2015-11-29 11:58:40 +01:00
} elseif ( isset ( $data [ 'is_quote' ]) && filter_var ( $data [ 'is_quote' ], FILTER_VALIDATE_BOOLEAN )) {
2015-10-28 20:22:07 +01:00
$entityType = ENTITY_QUOTE ;
2015-01-11 12:56:58 +01:00
}
2015-10-25 08:13:06 +01:00
$invoice = $account -> createInvoice ( $entityType , $data [ 'client_id' ]);
2017-01-30 13:40:48 +01:00
$invoice -> invoice_date = date_create () -> format ( 'Y-m-d' );
2017-03-16 18:51:38 +01:00
$invoice -> custom_taxes1 = $account -> custom_invoice_taxes1 ? : false ;
$invoice -> custom_taxes2 = $account -> custom_invoice_taxes2 ? : false ;
2017-01-30 13:35:04 +01:00
// set the default due date
2018-04-15 12:25:28 +02:00
if ( $entityType == ENTITY_INVOICE && empty ( $data [ 'partial_due_date' ])) {
2017-01-30 13:35:04 +01:00
$client = Client :: scope () -> whereId ( $data [ 'client_id' ]) -> first ();
$invoice -> due_date = $account -> defaultDueDate ( $client );
2017-01-16 12:59:46 +01:00
}
2015-10-28 20:22:07 +01:00
} else {
$invoice = Invoice :: scope ( $publicId ) -> firstOrFail ();
2016-10-10 10:40:04 +02:00
if ( Utils :: isNinjaDev ()) {
\Log :: warning ( 'Entity not set in invoice repo save' );
}
}
if ( $invoice -> is_deleted ) {
return $invoice ;
2018-02-15 09:43:07 +01:00
} elseif ( $invoice -> isLocked ()) {
2017-10-18 13:01:53 +02:00
return $invoice ;
2015-01-11 12:56:58 +01:00
}
2015-02-27 09:10:23 +01:00
2017-09-24 11:50:59 +02:00
if ( isset ( $data [ 'has_tasks' ]) && filter_var ( $data [ 'has_tasks' ], FILTER_VALIDATE_BOOLEAN )) {
$invoice -> has_tasks = true ;
}
if ( isset ( $data [ 'has_expenses' ]) && filter_var ( $data [ 'has_expenses' ], FILTER_VALIDATE_BOOLEAN )) {
$invoice -> has_expenses = true ;
}
2017-01-13 12:53:06 +01:00
if ( isset ( $data [ 'is_public' ]) && filter_var ( $data [ 'is_public' ], FILTER_VALIDATE_BOOLEAN )) {
2016-12-04 22:26:38 +01:00
$invoice -> is_public = true ;
2017-01-30 17:05:31 +01:00
if ( ! $invoice -> isSent ()) {
2016-12-04 22:26:38 +01:00
$invoice -> invoice_status_id = INVOICE_STATUS_SENT ;
}
}
2017-07-09 15:02:54 +02:00
if ( isset ( $data [ 'invoice_design_id' ]) && ! $data [ 'invoice_design_id' ]) {
$data [ 'invoice_design_id' ] = 1 ;
2017-06-26 10:20:01 +02:00
}
2017-07-09 15:02:54 +02:00
$invoice -> fill ( $data );
2015-04-13 14:00:31 +02:00
if (( isset ( $data [ 'set_default_terms' ]) && $data [ 'set_default_terms' ])
|| ( isset ( $data [ 'set_default_footer' ]) && $data [ 'set_default_footer' ])) {
if ( isset ( $data [ 'set_default_terms' ]) && $data [ 'set_default_terms' ]) {
2015-11-11 13:17:58 +01:00
$account -> { " { $invoice -> getEntityType () } _terms " } = trim ( $data [ 'terms' ]);
2015-04-13 14:00:31 +02:00
}
if ( isset ( $data [ 'set_default_footer' ]) && $data [ 'set_default_footer' ]) {
$account -> invoice_footer = trim ( $data [ 'invoice_footer' ]);
}
$account -> save ();
2016-05-29 14:34:44 +02:00
}
2015-04-13 14:00:31 +02:00
2017-01-30 20:40:43 +01:00
if ( ! empty ( $data [ 'invoice_number' ]) && ! $invoice -> is_recurring ) {
2015-07-30 16:44:47 +02:00
$invoice -> invoice_number = trim ( $data [ 'invoice_number' ]);
}
2015-11-18 15:40:50 +01:00
if ( isset ( $data [ 'discount' ])) {
$invoice -> discount = round ( Utils :: parseFloat ( $data [ 'discount' ]), 2 );
}
if ( isset ( $data [ 'is_amount_discount' ])) {
$invoice -> is_amount_discount = $data [ 'is_amount_discount' ] ? true : false ;
}
2017-10-26 09:56:59 +02:00
2016-01-06 21:46:11 +01:00
if ( isset ( $data [ 'invoice_date_sql' ])) {
$invoice -> invoice_date = $data [ 'invoice_date_sql' ];
} elseif ( isset ( $data [ 'invoice_date' ])) {
$invoice -> invoice_date = Utils :: toSqlDate ( $data [ 'invoice_date' ]);
}
2015-11-02 23:05:28 +01:00
2017-06-14 11:42:33 +02:00
/*
2017-01-30 17:05:31 +01:00
if ( isset ( $data [ 'invoice_status_id' ])) {
if ( $data [ 'invoice_status_id' ] == 0 ) {
2016-01-27 11:00:00 +01:00
$data [ 'invoice_status_id' ] = INVOICE_STATUS_DRAFT ;
}
$invoice -> invoice_status_id = $data [ 'invoice_status_id' ];
}
2017-06-14 11:42:33 +02:00
*/
2016-01-27 11:00:00 +01:00
2015-01-11 12:56:58 +01:00
if ( $invoice -> is_recurring ) {
2017-05-24 20:22:24 +02:00
if ( ! $isNew && isset ( $data [ 'start_date' ]) && $invoice -> start_date && $invoice -> start_date != Utils :: toSqlDate ( $data [ 'start_date' ])) {
2015-09-20 23:05:02 +02:00
$invoice -> last_sent_date = null ;
}
2017-06-28 16:39:32 +02:00
$invoice -> frequency_id = array_get ( $data , 'frequency_id' , FREQUENCY_MONTHLY );
2017-01-29 12:32:16 +01:00
$invoice -> start_date = Utils :: toSqlDate ( array_get ( $data , 'start_date' ));
$invoice -> end_date = Utils :: toSqlDate ( array_get ( $data , 'end_date' ));
2016-05-09 22:29:02 +02:00
$invoice -> client_enable_auto_bill = isset ( $data [ 'client_enable_auto_bill' ]) && $data [ 'client_enable_auto_bill' ] ? true : false ;
2017-01-29 12:32:16 +01:00
$invoice -> auto_bill = array_get ( $data , 'auto_bill_id' ) ? : array_get ( $data , 'auto_bill' , AUTO_BILL_OFF );
2016-05-06 19:26:37 +02:00
2017-01-30 17:05:31 +01:00
if ( $invoice -> auto_bill < AUTO_BILL_OFF || $invoice -> auto_bill > AUTO_BILL_ALWAYS ) {
2016-05-09 22:29:02 +02:00
$invoice -> auto_bill = AUTO_BILL_OFF ;
}
2016-05-29 14:34:44 +02:00
2016-01-12 13:24:25 +01:00
if ( isset ( $data [ 'recurring_due_date' ])) {
2016-01-01 05:59:02 +01:00
$invoice -> due_date = $data [ 'recurring_due_date' ];
2016-01-12 13:24:25 +01:00
} elseif ( isset ( $data [ 'due_date' ])) {
$invoice -> due_date = $data [ 'due_date' ];
2016-01-01 05:59:02 +01:00
}
2015-01-11 12:56:58 +01:00
} else {
2017-07-09 20:38:04 +02:00
if ( $isNew && empty ( $data [ 'due_date' ]) && empty ( $data [ 'due_date_sql' ])) {
2017-07-09 20:34:41 +02:00
// do nothing
} elseif ( isset ( $data [ 'due_date' ]) || isset ( $data [ 'due_date_sql' ])) {
2015-11-18 15:40:50 +01:00
$invoice -> due_date = isset ( $data [ 'due_date_sql' ]) ? $data [ 'due_date_sql' ] : Utils :: toSqlDate ( $data [ 'due_date' ]);
}
2015-01-11 12:56:58 +01:00
$invoice -> frequency_id = 0 ;
$invoice -> start_date = null ;
$invoice -> end_date = null ;
}
2016-04-20 10:04:54 +02:00
if ( isset ( $data [ 'terms' ]) && trim ( $data [ 'terms' ])) {
$invoice -> terms = trim ( $data [ 'terms' ]);
2016-12-29 21:40:24 +01:00
} elseif ( $isNew && ! $invoice -> is_recurring && $account -> { " { $entityType } _terms " }) {
2016-04-20 10:04:54 +02:00
$invoice -> terms = $account -> { " { $entityType } _terms " };
} else {
$invoice -> terms = '' ;
}
2016-05-29 14:34:44 +02:00
2017-10-24 21:12:53 +02:00
if ( isset ( $data [ 'invoice_footer' ]) && trim ( $data [ 'invoice_footer' ])) {
$invoice -> invoice_footer = trim ( $data [ 'invoice_footer' ]);
} elseif ( $isNew && ! $invoice -> is_recurring && $account -> invoice_footer ) {
$invoice -> invoice_footer = $account -> invoice_footer ;
} else {
$invoice -> invoice_footer = '' ;
}
2015-06-03 19:55:48 +02:00
2017-11-19 10:06:15 +01:00
$invoice -> public_notes = isset ( $data [ 'public_notes' ]) ? trim ( $data [ 'public_notes' ]) : '' ;
2016-05-02 22:10:54 +02:00
// process date variables if not recurring
2017-01-30 20:40:43 +01:00
if ( ! $invoice -> is_recurring ) {
2016-05-02 22:10:54 +02:00
$invoice -> terms = Utils :: processVariables ( $invoice -> terms );
$invoice -> invoice_footer = Utils :: processVariables ( $invoice -> invoice_footer );
$invoice -> public_notes = Utils :: processVariables ( $invoice -> public_notes );
}
2015-06-03 19:55:48 +02:00
2015-12-08 11:10:20 +01:00
if ( isset ( $data [ 'po_number' ])) {
$invoice -> po_number = trim ( $data [ 'po_number' ]);
}
2016-01-10 11:25:05 +01:00
2017-01-07 00:04:39 +01:00
// provide backwards compatibility
2016-03-31 11:29:01 +02:00
if ( isset ( $data [ 'tax_name' ]) && isset ( $data [ 'tax_rate' ])) {
2016-05-29 14:34:44 +02:00
$data [ 'tax_name1' ] = $data [ 'tax_name' ];
$data [ 'tax_rate1' ] = $data [ 'tax_rate' ];
2015-01-11 12:56:58 +01:00
}
$total = 0 ;
2015-08-12 21:16:02 +02:00
$itemTax = 0 ;
2015-01-11 12:56:58 +01:00
foreach ( $data [ 'invoice_items' ] as $item ) {
2015-02-27 09:10:23 +01:00
$item = ( array ) $item ;
2017-01-30 20:40:43 +01:00
if ( ! $item [ 'cost' ] && ! $item [ 'product_key' ] && ! $item [ 'notes' ]) {
2015-01-11 12:56:58 +01:00
continue ;
}
2017-08-14 13:06:50 +02:00
$invoiceItemCost = Utils :: roundSignificant ( Utils :: parseFloat ( $item [ 'cost' ]));
$invoiceItemQty = Utils :: roundSignificant ( Utils :: parseFloat ( $item [ 'qty' ]));
2017-12-30 20:22:03 +01:00
$discount = empty ( $item [ 'discount' ]) ? 0 : round ( Utils :: parseFloat ( $item [ 'discount' ]), 2 );
2015-01-11 12:56:58 +01:00
2015-08-12 21:16:02 +02:00
$lineTotal = $invoiceItemCost * $invoiceItemQty ;
2017-12-21 18:56:07 +01:00
2017-12-30 20:22:03 +01:00
if ( $discount ) {
2017-12-21 18:56:07 +01:00
if ( $invoice -> is_amount_discount ) {
$lineTotal -= $discount ;
} else {
2018-04-01 18:40:53 +02:00
$lineTotal -= round ( $lineTotal * $discount / 100 , 4 );
2017-12-21 18:56:07 +01:00
}
}
2015-08-12 21:16:02 +02:00
$total += round ( $lineTotal , 2 );
}
foreach ( $data [ 'invoice_items' ] as $item ) {
$item = ( array ) $item ;
2017-08-14 13:06:50 +02:00
$invoiceItemCost = Utils :: roundSignificant ( Utils :: parseFloat ( $item [ 'cost' ]));
$invoiceItemQty = Utils :: roundSignificant ( Utils :: parseFloat ( $item [ 'qty' ]));
2017-12-30 20:22:03 +01:00
$discount = empty ( $item [ 'discount' ]) ? 0 : round ( Utils :: parseFloat ( $item [ 'discount' ]), 2 );
2016-03-31 11:29:01 +02:00
$lineTotal = $invoiceItemCost * $invoiceItemQty ;
2017-12-30 20:22:03 +01:00
if ( $discount ) {
2017-12-21 18:56:07 +01:00
if ( $invoice -> is_amount_discount ) {
$lineTotal -= $discount ;
} else {
2018-04-01 18:40:53 +02:00
$lineTotal -= round ( $lineTotal * $discount / 100 , 4 );
2017-12-21 18:56:07 +01:00
}
}
2016-03-31 11:29:01 +02:00
if ( $invoice -> discount > 0 ) {
if ( $invoice -> is_amount_discount ) {
2017-07-18 11:26:19 +02:00
if ( $total != 0 ) {
2018-04-01 18:40:53 +02:00
$lineTotal -= round (( $lineTotal / $total ) * $invoice -> discount , 4 );
2017-07-18 11:26:19 +02:00
}
2016-03-31 11:29:01 +02:00
} else {
2018-04-01 18:40:53 +02:00
$lineTotal -= round ( $lineTotal * ( $invoice -> discount / 100 ), 4 );
2015-08-12 21:16:02 +02:00
}
2016-03-31 11:29:01 +02:00
}
2015-01-11 12:56:58 +01:00
2017-06-21 13:02:03 +02:00
if ( isset ( $item [ 'tax_rate1' ])) {
$taxRate1 = Utils :: parseFloat ( $item [ 'tax_rate1' ]);
if ( $taxRate1 != 0 ) {
$itemTax += round ( $lineTotal * $taxRate1 / 100 , 2 );
}
2016-03-31 11:29:01 +02:00
}
2017-06-21 13:02:03 +02:00
if ( isset ( $item [ 'tax_rate2' ])) {
$taxRate2 = Utils :: parseFloat ( $item [ 'tax_rate2' ]);
if ( $taxRate2 != 0 ) {
$itemTax += round ( $lineTotal * $taxRate2 / 100 , 2 );
}
2015-08-12 21:16:02 +02:00
}
2015-01-11 12:56:58 +01:00
}
2017-12-30 20:22:03 +01:00
if ( $invoice -> discount != 0 ) {
2015-01-11 12:56:58 +01:00
if ( $invoice -> is_amount_discount ) {
$total -= $invoice -> discount ;
} else {
2017-01-30 20:40:43 +01:00
$discount = round ( $total * ( $invoice -> discount / 100 ), 2 );
2017-01-25 12:04:45 +01:00
$total -= $discount ;
2015-01-11 12:56:58 +01:00
}
}
2015-12-07 14:34:55 +01:00
2015-10-28 20:22:07 +01:00
if ( isset ( $data [ 'custom_value1' ])) {
$invoice -> custom_value1 = round ( $data [ 'custom_value1' ], 2 );
}
if ( isset ( $data [ 'custom_value2' ])) {
$invoice -> custom_value2 = round ( $data [ 'custom_value2' ], 2 );
}
2015-12-07 14:34:55 +01:00
2015-10-11 16:41:09 +02:00
if ( isset ( $data [ 'custom_text_value1' ])) {
$invoice -> custom_text_value1 = trim ( $data [ 'custom_text_value1' ]);
}
if ( isset ( $data [ 'custom_text_value2' ])) {
$invoice -> custom_text_value2 = trim ( $data [ 'custom_text_value2' ]);
}
2015-01-11 12:56:58 +01:00
// custom fields charged taxes
if ( $invoice -> custom_value1 && $invoice -> custom_taxes1 ) {
$total += $invoice -> custom_value1 ;
}
if ( $invoice -> custom_value2 && $invoice -> custom_taxes2 ) {
$total += $invoice -> custom_value2 ;
}
2017-12-03 12:56:10 +01:00
if ( ! $account -> inclusive_taxes ) {
$taxAmount1 = round ( $total * ( $invoice -> tax_rate1 ? $invoice -> tax_rate1 : 0 ) / 100 , 2 );
$taxAmount2 = round ( $total * ( $invoice -> tax_rate2 ? $invoice -> tax_rate2 : 0 ) / 100 , 2 );
$total = round ( $total + $taxAmount1 + $taxAmount2 , 2 );
$total += $itemTax ;
}
2015-01-11 12:56:58 +01:00
// custom fields not charged taxes
2017-01-30 20:40:43 +01:00
if ( $invoice -> custom_value1 && ! $invoice -> custom_taxes1 ) {
2015-01-11 12:56:58 +01:00
$total += $invoice -> custom_value1 ;
}
2017-01-30 20:40:43 +01:00
if ( $invoice -> custom_value2 && ! $invoice -> custom_taxes2 ) {
2015-01-11 12:56:58 +01:00
$total += $invoice -> custom_value2 ;
}
if ( $publicId ) {
2017-03-01 14:16:48 +01:00
$invoice -> balance = round ( $total - ( $invoice -> amount - $invoice -> balance ), 2 );
2015-01-11 12:56:58 +01:00
} else {
$invoice -> balance = $total ;
}
2016-09-21 16:07:01 +02:00
if ( isset ( $data [ 'partial' ])) {
2017-01-30 17:05:31 +01:00
$invoice -> partial = max ( 0 , min ( round ( Utils :: parseFloat ( $data [ 'partial' ]), 2 ), $invoice -> balance ));
2016-09-21 16:07:01 +02:00
}
2017-10-26 09:56:59 +02:00
if ( $invoice -> partial ) {
if ( isset ( $data [ 'partial_due_date' ])) {
$invoice -> partial_due_date = Utils :: toSqlDate ( $data [ 'partial_due_date' ]);
}
} else {
$invoice -> partial_due_date = null ;
}
2015-01-11 12:56:58 +01:00
$invoice -> amount = $total ;
$invoice -> save ();
2015-02-27 09:10:23 +01:00
if ( $publicId ) {
$invoice -> invoice_items () -> forceDelete ();
}
2016-05-29 14:34:44 +02:00
2017-01-30 17:05:31 +01:00
if ( ! empty ( $data [ 'document_ids' ])) {
2016-10-23 10:01:21 +02:00
$document_ids = array_map ( 'intval' , $data [ 'document_ids' ]);
2017-01-30 17:05:31 +01:00
foreach ( $document_ids as $document_id ) {
2016-10-23 10:01:21 +02:00
$document = Document :: scope ( $document_id ) -> first ();
2017-01-30 17:05:31 +01:00
if ( $document && Auth :: user () -> can ( 'edit' , $document )) {
if ( $document -> invoice_id && $document -> invoice_id != $invoice -> id ) {
2016-10-23 10:01:21 +02:00
// From a clone
$document = $document -> cloneDocument ();
2017-01-30 20:40:43 +01:00
$document_ids [] = $document -> public_id ; // Don't remove this document
2016-10-23 10:01:21 +02:00
}
2016-05-29 14:34:44 +02:00
2016-10-23 10:01:21 +02:00
$document -> invoice_id = $invoice -> id ;
$document -> expense_id = null ;
$document -> save ();
}
2016-03-23 03:23:45 +01:00
}
2016-05-29 14:34:44 +02:00
2017-01-30 17:05:31 +01:00
if ( ! $invoice -> wasRecentlyCreated ) {
foreach ( $invoice -> documents as $document ) {
2017-01-30 20:40:43 +01:00
if ( ! in_array ( $document -> public_id , $document_ids )) {
2016-10-23 10:01:21 +02:00
// Removed
// Not checking permissions; deleting a document is just editing the invoice
2017-01-30 17:05:31 +01:00
if ( $document -> invoice_id == $invoice -> id ) {
2016-10-23 10:01:21 +02:00
// Make sure the document isn't on a clone
$document -> delete ();
}
2016-06-02 21:03:59 +02:00
}
2016-03-23 03:23:45 +01:00
}
}
}
2015-01-11 12:56:58 +01:00
foreach ( $data [ 'invoice_items' ] as $item ) {
2015-02-27 09:10:23 +01:00
$item = ( array ) $item ;
2016-02-28 12:59:52 +01:00
if ( empty ( $item [ 'cost' ]) && empty ( $item [ 'product_key' ]) && empty ( $item [ 'notes' ]) && empty ( $item [ 'custom_value1' ]) && empty ( $item [ 'custom_value2' ])) {
2015-01-11 12:56:58 +01:00
continue ;
}
2016-01-27 21:38:21 +01:00
$task = false ;
2015-05-27 18:52:10 +02:00
if ( isset ( $item [ 'task_public_id' ]) && $item [ 'task_public_id' ]) {
$task = Task :: scope ( $item [ 'task_public_id' ]) -> where ( 'invoice_id' , '=' , null ) -> firstOrFail ();
2017-01-30 17:05:31 +01:00
if ( Auth :: user () -> can ( 'edit' , $task )) {
2016-03-16 03:07:11 +01:00
$task -> invoice_id = $invoice -> id ;
$task -> client_id = $invoice -> client_id ;
$task -> save ();
}
2015-12-13 21:12:54 +01:00
}
2015-08-13 07:45:48 +02:00
2016-01-27 21:38:21 +01:00
$expense = false ;
2016-01-10 11:25:05 +01:00
if ( isset ( $item [ 'expense_public_id' ]) && $item [ 'expense_public_id' ]) {
$expense = Expense :: scope ( $item [ 'expense_public_id' ]) -> where ( 'invoice_id' , '=' , null ) -> firstOrFail ();
2017-01-30 17:05:31 +01:00
if ( Auth :: user () -> can ( 'edit' , $expense )) {
2016-03-16 03:07:11 +01:00
$expense -> invoice_id = $invoice -> id ;
$expense -> client_id = $invoice -> client_id ;
$expense -> save ();
}
2016-01-10 11:25:05 +01:00
}
2017-03-17 15:58:33 +01:00
if ( Auth :: check ()) {
if ( $productKey = trim ( $item [ 'product_key' ])) {
if ( $account -> update_products
&& ! $invoice -> has_tasks
&& ! $invoice -> has_expenses
2019-01-30 11:45:46 +01:00
&& ! in_array ( $productKey , Utils :: trans ([ 'surcharge' , 'discount' , 'fee' , 'gateway_fee_item' ]))
2017-03-17 15:58:33 +01:00
) {
$product = Product :: findProductByKey ( $productKey );
if ( ! $product ) {
if ( Auth :: user () -> can ( 'create' , ENTITY_PRODUCT )) {
$product = Product :: createNew ();
$product -> product_key = trim ( $item [ 'product_key' ]);
} else {
$product = null ;
}
}
if ( $product && ( Auth :: user () -> can ( 'edit' , $product ))) {
$product -> notes = ( $task || $expense ) ? '' : $item [ 'notes' ];
2017-12-24 10:45:18 +01:00
if ( ! $account -> convert_products ) {
2018-02-14 18:58:48 +01:00
$product -> cost = $expense ? 0 : Utils :: parseFloat ( $item [ 'cost' ]);
2017-12-24 10:45:18 +01:00
}
2017-05-17 12:21:20 +02:00
$product -> tax_name1 = isset ( $item [ 'tax_name1' ]) ? $item [ 'tax_name1' ] : null ;
$product -> tax_rate1 = isset ( $item [ 'tax_rate1' ]) ? $item [ 'tax_rate1' ] : 0 ;
$product -> tax_name2 = isset ( $item [ 'tax_name2' ]) ? $item [ 'tax_name2' ] : null ;
$product -> tax_rate2 = isset ( $item [ 'tax_rate2' ]) ? $item [ 'tax_rate2' ] : 0 ;
2017-03-17 15:58:33 +01:00
$product -> custom_value1 = isset ( $item [ 'custom_value1' ]) ? $item [ 'custom_value1' ] : null ;
$product -> custom_value2 = isset ( $item [ 'custom_value2' ]) ? $item [ 'custom_value2' ] : null ;
$product -> save ();
2016-03-16 03:07:11 +01:00
}
2015-12-27 12:08:58 +01:00
}
2015-01-11 12:56:58 +01:00
}
}
2017-03-17 15:58:33 +01:00
$invoiceItem = InvoiceItem :: createNew ( $invoice );
2017-03-17 12:47:16 +01:00
$invoiceItem -> fill ( $item );
2015-01-11 12:56:58 +01:00
$invoiceItem -> product_id = isset ( $product ) ? $product -> id : null ;
2015-11-18 15:40:50 +01:00
$invoiceItem -> product_key = isset ( $item [ 'product_key' ]) ? ( trim ( $invoice -> is_recurring ? $item [ 'product_key' ] : Utils :: processVariables ( $item [ 'product_key' ]))) : '' ;
2015-02-27 09:10:23 +01:00
$invoiceItem -> notes = trim ( $invoice -> is_recurring ? $item [ 'notes' ] : Utils :: processVariables ( $item [ 'notes' ]));
$invoiceItem -> cost = Utils :: parseFloat ( $item [ 'cost' ]);
$invoiceItem -> qty = Utils :: parseFloat ( $item [ 'qty' ]);
2015-01-11 12:56:58 +01:00
2016-02-28 12:59:52 +01:00
if ( isset ( $item [ 'custom_value1' ])) {
$invoiceItem -> custom_value1 = $item [ 'custom_value1' ];
}
if ( isset ( $item [ 'custom_value2' ])) {
$invoiceItem -> custom_value2 = $item [ 'custom_value2' ];
}
2016-03-31 11:29:01 +02:00
// provide backwards compatability
if ( isset ( $item [ 'tax_name' ]) && isset ( $item [ 'tax_rate' ])) {
2016-05-29 14:34:44 +02:00
$item [ 'tax_name1' ] = $item [ 'tax_name' ];
$item [ 'tax_rate1' ] = $item [ 'tax_rate' ];
2015-01-11 12:56:58 +01:00
}
2017-03-26 09:54:04 +02:00
// provide backwards compatability
if ( ! isset ( $item [ 'invoice_item_type_id' ]) && in_array ( $invoiceItem -> notes , [ trans ( 'texts.online_payment_surcharge' ), trans ( 'texts.online_payment_discount' )])) {
$invoiceItem -> invoice_item_type_id = $invoice -> balance > 0 ? INVOICE_ITEM_TYPE_PENDING_GATEWAY_FEE : INVOICE_ITEM_TYPE_PAID_GATEWAY_FEE ;
}
2016-03-31 11:29:01 +02:00
$invoiceItem -> fill ( $item );
2016-05-29 14:34:44 +02:00
2015-01-11 12:56:58 +01:00
$invoice -> invoice_items () -> save ( $invoiceItem );
}
2017-04-09 08:41:02 +02:00
$invoice -> load ( 'invoice_items' );
2017-03-30 19:45:07 +02:00
if ( Auth :: check ()) {
$invoice = $this -> saveInvitations ( $invoice );
}
2017-03-28 10:55:02 +02:00
2017-04-09 08:41:02 +02:00
$this -> dispatchEvents ( $invoice );
2017-04-06 20:31:29 +02:00
2017-03-28 10:55:02 +02:00
return $invoice ;
}
private function saveInvitations ( $invoice )
{
$client = $invoice -> client ;
$client -> load ( 'contacts' );
$sendInvoiceIds = [];
2018-01-16 14:48:56 +01:00
if ( ! $client -> contacts -> count ()) {
2017-04-24 09:35:30 +02:00
return $invoice ;
}
2017-03-28 10:55:02 +02:00
foreach ( $client -> contacts as $contact ) {
if ( $contact -> send_invoice ) {
$sendInvoiceIds [] = $contact -> id ;
}
}
2017-06-09 16:34:57 +02:00
// if no contacts are selected auto-select the first to ensure there's an invitation
2017-03-28 10:55:02 +02:00
if ( ! count ( $sendInvoiceIds )) {
$sendInvoiceIds [] = $client -> contacts [ 0 ] -> id ;
}
foreach ( $client -> contacts as $contact ) {
2019-01-30 11:45:46 +01:00
$invitations = Invitation :: scope () -> whereContactId ( $contact -> id ) -> whereInvoiceId ( $invoice -> id ) -> orderBy ( 'id' ) -> get ();
if ( $invitations -> count () == 0 ) {
if ( in_array ( $contact -> id , $sendInvoiceIds )) {
$invitation = Invitation :: createNew ( $invoice );
$invitation -> invoice_id = $invoice -> id ;
$invitation -> contact_id = $contact -> id ;
$invitation -> invitation_key = strtolower ( str_random ( RANDOM_KEY_LENGTH ));
$invitation -> save ();
}
} else {
$isFirst = true ;
foreach ( $invitations as $invitation ) {
if ( ! in_array ( $contact -> id , $sendInvoiceIds ) || ! $isFirst ) {
$invitation -> delete ();
}
$isFirst = false ;
}
2017-03-28 10:55:02 +02:00
}
}
if ( $invoice -> is_public && ! $invoice -> areInvitationsSent ()) {
$invoice -> markInvitationsSent ();
}
2015-01-11 12:56:58 +01:00
return $invoice ;
2014-05-20 23:40:09 +02:00
}
2015-01-11 12:56:58 +01:00
2017-04-09 08:41:02 +02:00
private function dispatchEvents ( $invoice )
2017-04-06 20:31:29 +02:00
{
if ( $invoice -> isType ( INVOICE_TYPE_QUOTE )) {
if ( $invoice -> wasRecentlyCreated ) {
2017-04-09 08:41:02 +02:00
event ( new QuoteItemsWereCreated ( $invoice ));
2017-04-06 20:31:29 +02:00
} else {
2017-04-09 08:41:02 +02:00
event ( new QuoteItemsWereUpdated ( $invoice ));
2017-04-06 20:31:29 +02:00
}
} else {
if ( $invoice -> wasRecentlyCreated ) {
2017-04-09 08:41:02 +02:00
event ( new InvoiceItemsWereCreated ( $invoice ));
2017-04-06 20:31:29 +02:00
} else {
2017-04-09 08:41:02 +02:00
event ( new InvoiceItemsWereUpdated ( $invoice ));
2017-04-06 20:31:29 +02:00
}
}
}
2016-07-03 18:11:58 +02:00
/**
* @ param Invoice $invoice
2017-08-29 17:24:10 +02:00
* @ param null $quoteId
2017-01-30 20:40:43 +01:00
*
2016-07-03 18:11:58 +02:00
* @ return mixed
*/
2017-08-29 17:24:10 +02:00
public function cloneInvoice ( Invoice $invoice , $quoteId = null )
2014-05-20 23:40:09 +02:00
{
2015-01-11 12:56:58 +01:00
$invoice -> load ( 'invitations' , 'invoice_items' );
$account = $invoice -> account ;
$clone = Invoice :: createNew ( $invoice );
$clone -> balance = $invoice -> amount ;
2014-05-20 23:40:09 +02:00
2015-11-06 09:21:45 +01:00
// if the invoice prefix is diff than quote prefix, use the same number for the invoice (if it's available)
$invoiceNumber = false ;
if ( $account -> hasInvoicePrefix () && $account -> share_counter ) {
2015-01-11 12:56:58 +01:00
$invoiceNumber = $invoice -> invoice_number ;
2015-06-07 10:05:30 +02:00
if ( $account -> quote_number_prefix && strpos ( $invoiceNumber , $account -> quote_number_prefix ) === 0 ) {
2015-01-11 12:56:58 +01:00
$invoiceNumber = substr ( $invoiceNumber , strlen ( $account -> quote_number_prefix ));
}
2015-12-07 14:34:55 +01:00
$invoiceNumber = $account -> invoice_number_prefix . $invoiceNumber ;
2015-12-23 12:49:49 +01:00
if ( Invoice :: scope ( false , $account -> id )
-> withTrashed ()
-> whereInvoiceNumber ( $invoiceNumber )
-> first ()) {
2015-11-06 09:21:45 +01:00
$invoiceNumber = false ;
2017-11-26 10:51:35 +01:00
} else {
// since we aren't using the counter we need to offset it by one
$account -> invoice_number_counter -= 1 ;
$account -> save ();
2015-11-06 09:21:45 +01:00
}
2015-01-11 12:56:58 +01:00
}
2014-05-20 23:40:09 +02:00
2015-01-11 12:56:58 +01:00
foreach ([
'client_id' ,
'discount' ,
'is_amount_discount' ,
'po_number' ,
'is_recurring' ,
'frequency_id' ,
'start_date' ,
'end_date' ,
'terms' ,
2015-02-28 22:42:47 +01:00
'invoice_footer' ,
2015-01-11 12:56:58 +01:00
'public_notes' ,
'invoice_design_id' ,
2016-03-31 11:29:01 +02:00
'tax_name1' ,
'tax_rate1' ,
'tax_name2' ,
'tax_rate2' ,
2015-01-11 12:56:58 +01:00
'amount' ,
2016-05-26 16:56:54 +02:00
'invoice_type_id' ,
2015-01-11 12:56:58 +01:00
'custom_value1' ,
'custom_value2' ,
'custom_taxes1' ,
2015-06-04 22:53:58 +02:00
'custom_taxes2' ,
2015-10-11 16:41:09 +02:00
'partial' ,
'custom_text_value1' ,
2016-12-04 22:26:38 +01:00
'custom_text_value2' ,
] as $field ) {
2015-01-11 12:56:58 +01:00
$clone -> $field = $invoice -> $field ;
}
2014-05-20 23:40:09 +02:00
2017-08-29 17:24:10 +02:00
if ( $quoteId ) {
2016-05-26 16:56:54 +02:00
$clone -> invoice_type_id = INVOICE_TYPE_STANDARD ;
2019-01-30 11:45:46 +01:00
$clone -> invoice_design_id = $account -> invoice_design_id ;
2017-08-29 17:24:10 +02:00
$clone -> quote_id = $quoteId ;
2016-10-05 21:11:22 +02:00
if ( $account -> invoice_terms ) {
$clone -> terms = $account -> invoice_terms ;
}
2017-10-17 13:12:04 +02:00
if ( ! auth () -> check ()) {
2016-12-05 09:11:33 +01:00
$clone -> is_public = true ;
$clone -> invoice_status_id = INVOICE_STATUS_SENT ;
}
2015-01-11 12:56:58 +01:00
}
2014-01-12 19:55:33 +01:00
2017-08-04 16:30:55 +02:00
$clone -> invoice_number = $invoiceNumber ? : $account -> getNextNumber ( $clone );
$clone -> invoice_date = date_create () -> format ( 'Y-m-d' );
$clone -> due_date = $account -> defaultDueDate ( $invoice -> client );
2015-01-11 12:56:58 +01:00
$clone -> save ();
2014-01-12 19:55:33 +01:00
2017-08-29 17:24:10 +02:00
if ( $quoteId ) {
2015-01-11 12:56:58 +01:00
$invoice -> quote_invoice_id = $clone -> public_id ;
$invoice -> save ();
}
foreach ( $invoice -> invoice_items as $item ) {
$cloneItem = InvoiceItem :: createNew ( $invoice );
foreach ([
'product_id' ,
'product_key' ,
'notes' ,
'cost' ,
'qty' ,
2016-03-31 11:29:01 +02:00
'tax_name1' ,
2016-05-29 14:34:44 +02:00
'tax_rate1' ,
2016-03-31 11:29:01 +02:00
'tax_name2' ,
2016-05-29 14:34:44 +02:00
'tax_rate2' ,
2017-02-07 15:19:07 +01:00
'custom_value1' ,
'custom_value2' ,
2018-03-10 23:19:36 +01:00
'discount' ,
2016-03-31 11:29:01 +02:00
] as $field ) {
2015-01-11 12:56:58 +01:00
$cloneItem -> $field = $item -> $field ;
}
$clone -> invoice_items () -> save ( $cloneItem );
}
2016-03-24 17:54:38 +01:00
foreach ( $invoice -> documents as $document ) {
2016-05-29 14:34:44 +02:00
$cloneDocument = $document -> cloneDocument ();
2016-09-28 09:43:48 +02:00
$clone -> documents () -> save ( $cloneDocument );
2016-03-24 17:54:38 +01:00
}
2015-01-11 12:56:58 +01:00
foreach ( $invoice -> invitations as $invitation ) {
$cloneInvitation = Invitation :: createNew ( $invoice );
$cloneInvitation -> contact_id = $invitation -> contact_id ;
2017-04-02 19:46:01 +02:00
$cloneInvitation -> invitation_key = strtolower ( str_random ( RANDOM_KEY_LENGTH ));
2015-01-11 12:56:58 +01:00
$clone -> invitations () -> save ( $cloneInvitation );
}
2017-09-14 10:51:11 +02:00
$this -> dispatchEvents ( $clone );
2015-01-11 12:56:58 +01:00
return $clone ;
}
2016-07-03 18:11:58 +02:00
/**
* @ param Invoice $invoice
*/
2017-01-11 14:53:26 +01:00
public function emailInvoice ( Invoice $invoice )
2015-01-11 12:56:58 +01:00
{
2017-02-02 13:05:51 +01:00
// TODO remove this with Laravel 5.3 (https://github.com/invoiceninja/invoiceninja/issues/1303)
if ( config ( 'queue.default' ) === 'sync' ) {
app ( 'App\Ninja\Mailers\ContactMailer' ) -> sendInvoice ( $invoice );
} else {
dispatch ( new SendInvoiceEmail ( $invoice ));
}
2017-01-11 14:53:26 +01:00
}
2016-12-19 10:48:33 +01:00
2016-07-03 18:11:58 +02:00
/**
* @ param Invoice $invoice
*/
public function markSent ( Invoice $invoice )
2015-01-11 12:56:58 +01:00
{
2017-01-13 08:02:22 +01:00
$invoice -> markSent ();
2016-12-14 20:47:22 +01:00
}
/**
* @ param Invoice $invoice
*/
public function markPaid ( Invoice $invoice )
{
2017-01-30 17:05:31 +01:00
if ( ! $invoice -> canBePaid ()) {
2016-12-14 20:47:22 +01:00
return ;
}
2017-01-13 12:53:06 +01:00
$invoice -> markSentIfUnsent ();
2016-12-29 12:11:14 +01:00
2016-12-14 20:47:22 +01:00
$data = [
'client_id' => $invoice -> client_id ,
'invoice_id' => $invoice -> id ,
'amount' => $invoice -> balance ,
];
return $this -> paymentRepo -> save ( $data );
2015-01-11 12:56:58 +01:00
}
2015-07-12 21:43:45 +02:00
2016-07-03 18:11:58 +02:00
/**
* @ param $invitationKey
2017-01-30 20:40:43 +01:00
*
2016-07-03 18:11:58 +02:00
* @ return Invitation | bool
*/
2015-10-13 09:11:44 +02:00
public function findInvoiceByInvitation ( $invitationKey )
{
2017-02-20 11:57:21 +01:00
// check for extra params at end of value (from website feature)
list ( $invitationKey ) = explode ( '&' , $invitationKey );
2017-03-26 22:18:25 +02:00
$invitationKey = substr ( $invitationKey , 0 , RANDOM_KEY_LENGTH );
2017-02-20 11:57:21 +01:00
2016-07-03 18:11:58 +02:00
/** @var \App\Models\Invitation $invitation */
2015-10-13 09:11:44 +02:00
$invitation = Invitation :: where ( 'invitation_key' , '=' , $invitationKey ) -> first ();
2015-10-20 19:12:34 +02:00
2017-01-30 20:40:43 +01:00
if ( ! $invitation ) {
2015-10-20 19:12:34 +02:00
return false ;
2015-10-13 09:11:44 +02:00
}
$invoice = $invitation -> invoice ;
2017-01-30 20:40:43 +01:00
if ( ! $invoice || $invoice -> is_deleted ) {
2015-10-20 19:12:34 +02:00
return false ;
2015-10-13 09:11:44 +02:00
}
2016-03-23 23:40:42 +01:00
$invoice -> load ( 'user' , 'invoice_items' , 'documents' , 'invoice_design' , 'account.country' , 'client.contacts' , 'client.country' );
2015-10-13 09:11:44 +02:00
$client = $invoice -> client ;
2017-01-30 20:40:43 +01:00
if ( ! $client || $client -> is_deleted ) {
2015-10-20 19:12:34 +02:00
return false ;
2015-10-13 09:11:44 +02:00
}
return $invitation ;
}
2016-07-03 18:11:58 +02:00
/**
* @ param $clientId
2017-01-30 20:49:42 +01:00
* @ param mixed $entityType
2017-01-30 20:40:43 +01:00
*
2016-07-03 18:11:58 +02:00
* @ return mixed
*/
2017-06-20 17:10:57 +02:00
public function findOpenInvoices ( $clientId )
2015-07-12 21:43:45 +02:00
{
2016-08-21 17:25:35 +02:00
$query = Invoice :: scope ()
2017-01-22 11:09:29 +01:00
-> invoiceType ( INVOICE_TYPE_STANDARD )
-> whereClientId ( $clientId )
-> whereIsRecurring ( false )
-> whereDeletedAt ( null )
-> where ( 'balance' , '>' , 0 );
2016-08-21 17:25:35 +02:00
2017-07-14 07:48:45 +02:00
return $query -> where ( 'invoice_status_id' , '<' , INVOICE_STATUS_PAID )
2015-07-12 21:43:45 +02:00
-> select ([ 'public_id' , 'invoice_number' ])
-> get ();
}
2015-08-10 17:48:41 +02:00
2016-07-03 18:11:58 +02:00
/**
* @ param Invoice $recurInvoice
2017-01-30 20:40:43 +01:00
*
2016-07-03 18:11:58 +02:00
* @ return mixed
*/
public function createRecurringInvoice ( Invoice $recurInvoice )
2015-08-10 17:48:41 +02:00
{
$recurInvoice -> load ( 'account.timezone' , 'invoice_items' , 'client' , 'user' );
2017-07-10 10:24:27 +02:00
$client = $recurInvoice -> client ;
2015-08-10 17:48:41 +02:00
2017-07-10 10:24:27 +02:00
if ( $client -> deleted_at ) {
2015-08-10 17:48:41 +02:00
return false ;
}
2017-01-30 20:40:43 +01:00
if ( ! $recurInvoice -> user -> confirmed ) {
2015-08-10 17:48:41 +02:00
return false ;
}
2017-01-30 20:40:43 +01:00
if ( ! $recurInvoice -> shouldSendToday ()) {
2015-08-10 17:48:41 +02:00
return false ;
}
$invoice = Invoice :: createNew ( $recurInvoice );
2016-12-05 09:11:33 +01:00
$invoice -> is_public = true ;
2016-06-20 16:14:43 +02:00
$invoice -> invoice_type_id = INVOICE_TYPE_STANDARD ;
2015-08-10 17:48:41 +02:00
$invoice -> client_id = $recurInvoice -> client_id ;
$invoice -> recurring_invoice_id = $recurInvoice -> id ;
2017-01-04 09:11:32 +01:00
$invoice -> invoice_number = $recurInvoice -> account -> getNextNumber ( $invoice );
2015-08-10 17:48:41 +02:00
$invoice -> amount = $recurInvoice -> amount ;
$invoice -> balance = $recurInvoice -> amount ;
2017-01-30 13:40:48 +01:00
$invoice -> invoice_date = date_create () -> format ( 'Y-m-d' );
2015-08-10 17:48:41 +02:00
$invoice -> discount = $recurInvoice -> discount ;
$invoice -> po_number = $recurInvoice -> po_number ;
2017-07-10 10:24:27 +02:00
$invoice -> public_notes = Utils :: processVariables ( $recurInvoice -> public_notes , $client );
$invoice -> terms = Utils :: processVariables ( $recurInvoice -> terms ? : $recurInvoice -> account -> invoice_terms , $client );
$invoice -> invoice_footer = Utils :: processVariables ( $recurInvoice -> invoice_footer ? : $recurInvoice -> account -> invoice_footer , $client );
2016-03-31 11:29:01 +02:00
$invoice -> tax_name1 = $recurInvoice -> tax_name1 ;
$invoice -> tax_rate1 = $recurInvoice -> tax_rate1 ;
$invoice -> tax_name2 = $recurInvoice -> tax_name2 ;
$invoice -> tax_rate2 = $recurInvoice -> tax_rate2 ;
2015-08-10 17:48:41 +02:00
$invoice -> invoice_design_id = $recurInvoice -> invoice_design_id ;
2015-10-28 20:22:07 +01:00
$invoice -> custom_value1 = $recurInvoice -> custom_value1 ? : 0 ;
$invoice -> custom_value2 = $recurInvoice -> custom_value2 ? : 0 ;
$invoice -> custom_taxes1 = $recurInvoice -> custom_taxes1 ? : 0 ;
$invoice -> custom_taxes2 = $recurInvoice -> custom_taxes2 ? : 0 ;
2017-07-10 10:24:27 +02:00
$invoice -> custom_text_value1 = Utils :: processVariables ( $recurInvoice -> custom_text_value1 , $client );
$invoice -> custom_text_value2 = Utils :: processVariables ( $recurInvoice -> custom_text_value2 , $client );
2015-08-10 17:48:41 +02:00
$invoice -> is_amount_discount = $recurInvoice -> is_amount_discount ;
2016-01-01 05:59:02 +01:00
$invoice -> due_date = $recurInvoice -> getDueDate ();
2015-08-10 17:48:41 +02:00
$invoice -> save ();
foreach ( $recurInvoice -> invoice_items as $recurItem ) {
$item = InvoiceItem :: createNew ( $recurItem );
$item -> product_id = $recurItem -> product_id ;
$item -> qty = $recurItem -> qty ;
$item -> cost = $recurItem -> cost ;
2017-07-10 10:24:27 +02:00
$item -> notes = Utils :: processVariables ( $recurItem -> notes , $client );
$item -> product_key = Utils :: processVariables ( $recurItem -> product_key , $client );
2016-03-31 11:29:01 +02:00
$item -> tax_name1 = $recurItem -> tax_name1 ;
$item -> tax_rate1 = $recurItem -> tax_rate1 ;
$item -> tax_name2 = $recurItem -> tax_name2 ;
$item -> tax_rate2 = $recurItem -> tax_rate2 ;
2017-07-10 10:24:27 +02:00
$item -> custom_value1 = Utils :: processVariables ( $recurItem -> custom_value1 , $client );
$item -> custom_value2 = Utils :: processVariables ( $recurItem -> custom_value2 , $client );
2018-03-10 23:19:36 +01:00
$item -> discount = $recurItem -> discount ;
2015-08-10 17:48:41 +02:00
$invoice -> invoice_items () -> save ( $item );
}
2016-03-24 17:54:38 +01:00
foreach ( $recurInvoice -> documents as $recurDocument ) {
$document = $recurDocument -> cloneDocument ();
$invoice -> documents () -> save ( $document );
}
2015-08-10 17:48:41 +02:00
foreach ( $recurInvoice -> invitations as $recurInvitation ) {
$invitation = Invitation :: createNew ( $recurInvitation );
$invitation -> contact_id = $recurInvitation -> contact_id ;
2017-04-02 19:46:01 +02:00
$invitation -> invitation_key = strtolower ( str_random ( RANDOM_KEY_LENGTH ));
2015-08-10 17:48:41 +02:00
$invoice -> invitations () -> save ( $invitation );
}
2015-09-10 19:50:09 +02:00
$recurInvoice -> last_sent_date = date ( 'Y-m-d' );
2015-08-10 17:48:41 +02:00
$recurInvoice -> save ();
2017-01-30 20:40:43 +01:00
if ( $recurInvoice -> getAutoBillEnabled () && ! $recurInvoice -> account -> auto_bill_on_due_date ) {
2016-05-26 21:22:09 +02:00
// autoBillInvoice will check for ACH, so we're not checking here
2015-09-10 19:50:09 +02:00
if ( $this -> paymentService -> autoBillInvoice ( $invoice )) {
2015-12-16 12:49:26 +01:00
// update the invoice reference to match its actual state
// this is to ensure a 'payment received' email is sent
2015-09-10 19:50:09 +02:00
$invoice -> invoice_status_id = INVOICE_STATUS_PAID ;
}
}
2017-06-09 12:07:50 +02:00
$this -> dispatchEvents ( $invoice );
2015-08-10 17:48:41 +02:00
return $invoice ;
}
2015-09-17 21:01:06 +02:00
2016-07-03 18:11:58 +02:00
/**
* @ param Account $account
2017-01-30 20:40:43 +01:00
*
2016-07-03 18:11:58 +02:00
* @ return mixed
*/
2017-07-18 20:15:51 +02:00
public function findNeedingReminding ( Account $account , $filterEnabled = true )
2015-09-17 21:01:06 +02:00
{
$dates = [];
2016-01-10 11:25:05 +01:00
2017-01-30 20:40:43 +01:00
for ( $i = 1 ; $i <= 3 ; $i ++ ) {
2017-07-18 20:15:51 +02:00
if ( $date = $account -> getReminderDate ( $i , $filterEnabled )) {
2017-10-26 09:56:59 +02:00
if ( $account -> { " field_reminder { $i } " } == REMINDER_FIELD_DUE_DATE ) {
$dates [] = " (due_date = ' $date ' OR partial_due_date = ' $date ') " ;
} else {
$dates [] = " invoice_date = ' $date ' " ;
}
2015-09-17 21:01:06 +02:00
}
}
2017-07-18 20:15:51 +02:00
if ( ! count ( $dates )) {
2018-03-19 15:43:42 +01:00
return collect ();
2017-07-18 20:15:51 +02:00
}
2015-12-28 11:15:56 +01:00
$sql = implode ( ' OR ' , $dates );
2016-05-26 16:56:54 +02:00
$invoices = Invoice :: invoiceType ( INVOICE_TYPE_STANDARD )
2017-12-04 22:21:59 +01:00
-> with ( 'client' , 'invoice_items' )
2017-11-30 18:33:27 +01:00
-> whereHas ( 'client' , function ( $query ) {
$query -> whereSendReminders ( true );
})
2016-05-26 16:56:54 +02:00
-> whereAccountId ( $account -> id )
2015-09-17 21:01:06 +02:00
-> where ( 'balance' , '>' , 0 )
2016-02-03 09:08:12 +01:00
-> where ( 'is_recurring' , '=' , false )
2017-02-02 07:17:05 +01:00
-> whereIsPublic ( true )
2015-12-07 14:34:55 +01:00
-> whereRaw ( '(' . $sql . ')' )
2015-09-17 21:01:06 +02:00
-> get ();
return $invoices ;
}
2017-12-26 11:03:23 +01:00
public function findNeedingEndlessReminding ( Account $account )
{
2018-01-14 14:20:45 +01:00
$settings = $account -> account_email_settings ;
$frequencyId = $settings -> frequency_id_reminder4 ;
2017-12-26 11:03:23 +01:00
2018-01-29 19:03:17 +01:00
if ( ! $frequencyId || ! $account -> enable_reminder4 ) {
2018-02-27 14:29:30 +01:00
return collect ();
2018-01-29 19:03:17 +01:00
}
2018-01-14 14:20:45 +01:00
$frequency = Utils :: getFromCache ( $frequencyId , 'frequencies' );
2017-12-26 11:03:23 +01:00
$lastSentDate = date_create ();
$lastSentDate -> sub ( date_interval_create_from_date_string ( $frequency -> date_interval ));
$invoices = Invoice :: invoiceType ( INVOICE_TYPE_STANDARD )
-> with ( 'client' , 'invoice_items' )
-> whereHas ( 'client' , function ( $query ) {
$query -> whereSendReminders ( true );
})
-> whereAccountId ( $account -> id )
-> where ( 'balance' , '>' , 0 )
-> where ( 'is_recurring' , '=' , false )
-> whereIsPublic ( true )
-> where ( 'last_sent_date' , '<' , $lastSentDate );
for ( $i = 1 ; $i <= 3 ; $i ++ ) {
if ( ! $account -> { " enable_reminder { $i } " }) {
continue ;
}
$field = $account -> { " field_reminder { $i } " } == REMINDER_FIELD_DUE_DATE ? 'due_date' : 'invoice_date' ;
$date = date_create ();
if ( $account -> { " direction_reminder { $i } " } == REMINDER_DIRECTION_AFTER ) {
$date -> sub ( date_interval_create_from_date_string ( $account -> { " num_days_reminder { $i } " } . ' days' ));
}
$invoices -> where ( $field , '<' , $date );
}
return $invoices -> get ();
}
2017-03-16 15:03:17 +01:00
2017-03-16 21:34:45 +01:00
public function clearGatewayFee ( $invoice )
2017-03-16 15:03:17 +01:00
{
$account = $invoice -> account ;
2017-03-17 12:47:16 +01:00
2017-03-17 14:10:33 +01:00
if ( ! $invoice -> relationLoaded ( 'invoice_items' )) {
$invoice -> load ( 'invoice_items' );
}
2017-03-26 09:37:32 +02:00
$data = $invoice -> toArray ();
foreach ( $data [ 'invoice_items' ] as $key => $item ) {
if ( $item [ 'invoice_item_type_id' ] == INVOICE_ITEM_TYPE_PENDING_GATEWAY_FEE ) {
unset ( $data [ 'invoice_items' ][ $key ]);
2017-03-17 12:47:16 +01:00
$this -> save ( $data , $invoice );
2017-03-26 09:37:32 +02:00
break ;
2017-03-16 15:03:17 +01:00
}
}
2017-03-16 21:34:45 +01:00
}
2017-07-18 20:15:51 +02:00
public function setLateFee ( $invoice , $amount , $percent )
{
if ( $amount <= 0 && $percent <= 0 ) {
return false ;
}
$account = $invoice -> account ;
$data = $invoice -> toArray ();
$fee = $amount ;
2018-04-29 08:02:34 +02:00
if ( $invoice -> getRequestedAmount () > 0 ) {
$fee += round ( $invoice -> getRequestedAmount () * $percent / 100 , 2 );
2017-07-18 20:15:51 +02:00
}
$item = [];
$item [ 'product_key' ] = trans ( 'texts.fee' );
$item [ 'notes' ] = trans ( 'texts.late_fee_added' , [ 'date' => $account -> formatDate ( 'now' )]);
$item [ 'qty' ] = 1 ;
$item [ 'cost' ] = $fee ;
$item [ 'invoice_item_type_id' ] = INVOICE_ITEM_TYPE_LATE_FEE ;
$data [ 'invoice_items' ][] = $item ;
$this -> save ( $data , $invoice );
}
2017-03-16 21:34:45 +01:00
public function setGatewayFee ( $invoice , $gatewayTypeId )
{
$account = $invoice -> account ;
2017-03-26 09:37:32 +02:00
if ( ! $account -> gateway_fee_enabled ) {
2017-03-16 21:34:45 +01:00
return ;
}
2017-03-26 09:37:32 +02:00
$settings = $account -> getGatewaySettings ( $gatewayTypeId );
2017-03-16 21:34:45 +01:00
$this -> clearGatewayFee ( $invoice );
2017-03-17 12:47:16 +01:00
if ( ! $settings ) {
return ;
}
2017-03-16 15:03:17 +01:00
$data = $invoice -> toArray ();
2017-03-26 09:37:32 +02:00
$fee = $invoice -> calcGatewayFee ( $gatewayTypeId );
2019-01-30 11:45:46 +01:00
if ( $fee == 0 ) {
return ;
}
2018-04-15 12:21:16 +02:00
$date = $account -> getDateTime () -> format ( $account -> getCustomDateFormat ());
$feeItemLabel = $account -> getLabel ( 'gateway_fee_item' ) ? : ( $fee >= 0 ? trans ( 'texts.surcharge' ) : trans ( 'texts.discount' ));
if ( $feeDescriptionLabel = $account -> getLabel ( 'gateway_fee_description' )) {
if ( strpos ( $feeDescriptionLabel , '$date' ) !== false ) {
$feeDescriptionLabel = str_replace ( '$date' , $date , $feeDescriptionLabel );
} else {
$feeDescriptionLabel .= ' • ' . $date ;
}
} else {
$feeDescriptionLabel = $fee >= 0 ? trans ( 'texts.online_payment_surcharge' ) : trans ( 'texts.online_payment_discount' );
$feeDescriptionLabel .= ' • ' . $date ;
}
2017-03-26 09:37:32 +02:00
$item = [];
2018-04-15 12:21:16 +02:00
$item [ 'product_key' ] = $feeItemLabel ;
$item [ 'notes' ] = $feeDescriptionLabel ;
2017-03-26 09:37:32 +02:00
$item [ 'qty' ] = 1 ;
$item [ 'cost' ] = $fee ;
$item [ 'tax_rate1' ] = $settings -> fee_tax_rate1 ;
$item [ 'tax_name1' ] = $settings -> fee_tax_name1 ;
$item [ 'tax_rate2' ] = $settings -> fee_tax_rate2 ;
$item [ 'tax_name2' ] = $settings -> fee_tax_name2 ;
$item [ 'invoice_item_type_id' ] = INVOICE_ITEM_TYPE_PENDING_GATEWAY_FEE ;
$data [ 'invoice_items' ][] = $item ;
2017-03-16 21:34:45 +01:00
2017-03-16 15:03:17 +01:00
$this -> save ( $data , $invoice );
}
2017-04-04 20:08:35 +02:00
public function findPhonetically ( $invoiceNumber )
{
$map = [];
$max = SIMILAR_MIN_THRESHOLD ;
$invoiceId = 0 ;
$invoices = Invoice :: scope () -> get ([ 'id' , 'invoice_number' , 'public_id' ]);
foreach ( $invoices as $invoice ) {
$map [ $invoice -> id ] = $invoice ;
$similar = similar_text ( $invoiceNumber , $invoice -> invoice_number , $percent );
var_dump ( $similar );
if ( $percent > $max ) {
$invoiceId = $invoice -> id ;
$max = $percent ;
}
}
return ( $invoiceId && isset ( $map [ $invoiceId ])) ? $map [ $invoiceId ] : null ;
}
2013-12-25 22:34:42 +01:00
}