Merge pull request #7793 from turbo124/v5-stable

v5.5.18
This commit is contained in:
David Bomba 2022-09-01 20:29:35 +10:00 committed by GitHub
commit fc8ea5392a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 192798 additions and 191109 deletions

View File

@ -12,7 +12,7 @@ jobs:
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: ['ubuntu-18.04', 'ubuntu-20.04', 'ubuntu-22.04']
operating-system: ['ubuntu-20.04', 'ubuntu-22.04']
php-versions: ['8.1']
phpunit-versions: ['latest']

View File

@ -1 +1 @@
5.5.17
5.5.18

View File

@ -29,6 +29,7 @@ use App\Models\Payment;
use App\Models\Paymentable;
use App\Models\QuoteInvitation;
use App\Models\RecurringInvoiceInvitation;
use App\Models\User;
use App\Models\Vendor;
use App\Utils\Ninja;
use Exception;
@ -114,6 +115,8 @@ class CheckData extends Command
$this->checkEntityInvitations();
$this->checkCompanyData();
$this->checkBalanceVsPaidStatus();
$this->checkDuplicateRecurringInvoices();
$this->checkOauthSanity();
if(Ninja::isHosted())
$this->checkAccountStatuses();
@ -145,6 +148,32 @@ class CheckData extends Command
$this->log .= $str."\n";
}
private function checkOauthSanity()
{
User::where('oauth_provider_id', '1')->cursor()->each(function ($user){
$this->logMessage("Invalid provider ID for user id# {$user->id}");
});
}
private function checkDuplicateRecurringInvoices()
{
if(Ninja::isHosted())
{
$c = Client::on('db-ninja-01')->where('company_id', config('ninja.ninja_default_company_id'))
->with('recurring_invoices')
->cursor()
->each(function ($client){
if($client->recurring_invoices()->where('is_deleted', 0)->where('deleted_at', null)->count() > 1)
$this->logMessage("Duplicate Recurring Invoice => {$client->custom_value1}");
});
}
}
private function checkOAuth()
{
// check for duplicate oauth ids
@ -937,7 +966,7 @@ class CheckData extends Command
{
$this->wrong_paid_status = 0;
foreach(Invoice::with(['payments'])->whereHas('payments')->where('status_id', 4)->where('balance', '>', 0)->where('is_deleted',0)->cursor() as $invoice)
foreach(Invoice::with(['payments'])->where('is_deleted',0)->where('balance', '>', 0)->whereHas('payments')->where('status_id', 4)->cursor() as $invoice)
{
$this->wrong_paid_status++;

View File

@ -168,6 +168,9 @@ class ClientFilters extends QueryFilters
{
$sort_col = explode('|', $sort);
if($sort_col[0] == 'display_name')
$sort_col[0] = 'name';
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
}

View File

@ -107,6 +107,7 @@ class ActivityController extends BaseController
'payment' => $activity->payment ? $activity->payment : '',
'credit' => $activity->credit ? $activity->credit : '',
'task' => $activity->task ? $activity->task : '',
'vendor' => $activity->vendor ? $activity->vendor : '',
];
return array_merge($arr, $activity->toArray());

View File

@ -351,7 +351,7 @@ class LoginController extends BaseController
private function handleSocialiteLogin($provider, $token)
{
$user = $this->getSocialiteUser($provider, $token);
nlog($user);
if ($user) {
return $this->loginOrCreateFromSocialite($user, $provider);
}
@ -368,6 +368,7 @@ class LoginController extends BaseController
'oauth_user_id' => $user->id,
'oauth_provider_id' => $provider,
];
if ($existing_user = MultiDB::hasUser($query)) {
if (!$existing_user->account) {
return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
@ -749,10 +750,6 @@ class LoginController extends BaseController
public function handleMicrosoftProviderCallback($provider = 'microsoft')
{
$socialite_user = Socialite::driver($provider)->user();
nlog($socialite_user);
nlog('refresh token ' . $socialite_user->accessTokenResponseBody['refresh_token']);
nlog('access token ' . $socialite_user->accessTokenResponseBody['access_token']);
$oauth_user_token = $socialite_user->accessTokenResponseBody['access_token'];

View File

@ -69,7 +69,7 @@ class InvoiceController extends Controller
$data = [
'invoice' => $invoice,
'invitation' => $invitation,
'invitation' => $invitation ?: $invoice->invitations->first(),
'key' => $invitation ? $invitation->key : false,
];

View File

@ -195,6 +195,7 @@ class NinjaPlanController extends Controller
public function plan()
{
// return $this->trial();
//harvest the current plan
$data = [];

View File

@ -101,7 +101,8 @@ class PaymentController extends Controller
$data = [
'invoice' => $invoice,
'key' => false
'key' => false,
'invitation' => $invoice->invitations->first()
];
if ($request->query('mode') === 'fullscreen') {

View File

@ -139,9 +139,14 @@ class Request extends FormRequest
$input['invitations'][$key]['id'] = $this->decodePrimaryKey($input['invitations'][$key]['id']);
}
if (is_string($input['invitations'][$key]['client_contact_id'])) {
if (array_key_exists('client_contact_id', $input['invitations'][$key]) && is_string($input['invitations'][$key]['client_contact_id'])) {
$input['invitations'][$key]['client_contact_id'] = $this->decodePrimaryKey($input['invitations'][$key]['client_contact_id']);
}
if (array_key_exists('vendor_contact_id', $input['invitations'][$key]) && is_string($input['invitations'][$key]['vendor_contact_id'])) {
$input['invitations'][$key]['vendor_contact_id'] = $this->decodePrimaryKey($input['invitations'][$key]['vendor_contact_id']);
}
}
}

View File

@ -33,6 +33,15 @@ class VendorMap
14 => 'vendor.state',
15 => 'vendor.postal_code',
16 => 'vendor.country_id',
17 => 'contact.first_name',
18 => 'contact.last_name',
19 => 'contact.email',
20 => 'contact.phone',
21 => 'contact.custom_value1',
22 => 'contact.custom_value2',
23 => 'contact.custom_value3',
24 => 'contact.custom_value4',
];
}
@ -56,6 +65,14 @@ class VendorMap
14 => 'texts.state',
15 => 'texts.postal_code',
16 => 'texts.country',
17 => 'texts.first_name',
18 => 'texts.last_name',
19 => 'texts.email',
20 => 'texts.phone',
21 => 'texts.custom_value',
22 => 'texts.custom_value',
23 => 'texts.custom_value',
24 => 'texts.custom_value',
];
}
}

View File

@ -16,12 +16,14 @@ use App\Factory\ExpenseFactory;
use App\Factory\InvoiceFactory;
use App\Factory\PaymentFactory;
use App\Factory\ProductFactory;
use App\Factory\QuoteFactory;
use App\Factory\VendorFactory;
use App\Http\Requests\Client\StoreClientRequest;
use App\Http\Requests\Expense\StoreExpenseRequest;
use App\Http\Requests\Invoice\StoreInvoiceRequest;
use App\Http\Requests\Payment\StorePaymentRequest;
use App\Http\Requests\Product\StoreProductRequest;
use App\Http\Requests\Quote\StoreQuoteRequest;
use App\Http\Requests\Vendor\StoreVendorRequest;
use App\Import\ImportException;
use App\Import\Providers\BaseImport;
@ -31,12 +33,14 @@ use App\Import\Transformer\Csv\ExpenseTransformer;
use App\Import\Transformer\Csv\InvoiceTransformer;
use App\Import\Transformer\Csv\PaymentTransformer;
use App\Import\Transformer\Csv\ProductTransformer;
use App\Import\Transformer\Csv\QuoteTransformer;
use App\Import\Transformer\Csv\VendorTransformer;
use App\Repositories\ClientRepository;
use App\Repositories\ExpenseRepository;
use App\Repositories\InvoiceRepository;
use App\Repositories\PaymentRepository;
use App\Repositories\ProductRepository;
use App\Repositories\QuoteRepository;
use App\Repositories\VendorRepository;
use Illuminate\Support\Facades\Validator;
use Symfony\Component\HttpFoundation\ParameterBag;
@ -55,6 +59,7 @@ class Csv extends BaseImport implements ImportInterface
'payment',
'vendor',
'expense',
'quote',
])
) {
$this->{$entity}();
@ -151,6 +156,35 @@ class Csv extends BaseImport implements ImportInterface
$this->entity_count['invoices'] = $invoice_count;
}
public function quote()
{
$entity_type = 'quote';
$data = $this->getCsvData($entity_type);
if (is_array($data)) {
$data = $this->preTransformCsv($data, $entity_type);
}
if (empty($data)) {
$this->entity_count['quotes'] = 0;
return;
}
$this->request_name = StoreQuoteRequest::class;
$this->repository_name = QuoteRepository::class;
$this->factory_name = QuoteFactory::class;
$this->repository = app()->make($this->repository_name);
$this->repository->import_mode = true;
$this->transformer = new QuoteTransformer($this->company);
$quote_count = $this->ingestQuotes($data, 'quote.number');
$this->entity_count['quotes'] = $quote_count;
}
public function payment()
{
$entity_type = 'payment';
@ -241,10 +275,6 @@ class Csv extends BaseImport implements ImportInterface
$this->entity_count['expenses'] = $expense_count;
}
public function quote()
{
}
public function task()
{
}

View File

@ -19,6 +19,14 @@ use App\Models\Country;
use App\Models\ExpenseCategory;
use App\Models\PaymentType;
use App\Models\User;
use App\Models\Expense;
use App\Models\Project;
use App\Models\Invoice;
use App\Models\Quote;
use App\Models\Client;
use App\Models\TaxRate;
use App\Models\Product;
use App\Models\Vendor;
use App\Utils\Number;
use Exception;
use Illuminate\Support\Carbon;
@ -67,8 +75,7 @@ class BaseTransformer
{
if (! empty($client_name)) {
$client_id_search = $this->company
->clients()
$client_id_search = Client::where('company_id', $this->company->id)
->where('is_deleted', false)
->where('id_number', $client_name);
@ -76,8 +83,7 @@ class BaseTransformer
return $client_id_search->first()->id;
}
$client_name_search = $this->company
->clients()
$client_name_search = Client::where('company_id', $this->company->id)
->where('is_deleted', false)
->where('name', $client_name);
@ -108,8 +114,7 @@ class BaseTransformer
*/
public function hasClient($name)
{
return $this->company
->clients()
return Client::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $name)),
@ -124,8 +129,7 @@ class BaseTransformer
*/
public function hasVendor($name)
{
return $this->company
->vendors()
return Vendor::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $name)),
@ -140,8 +144,7 @@ class BaseTransformer
*/
public function hasProject($name)
{
return $this->company
->projects()
return Project::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $name)),
@ -156,8 +159,7 @@ class BaseTransformer
*/
public function hasProduct($key)
{
return $this->company
->products()
return Product::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`product_key`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $key)),
@ -189,8 +191,7 @@ class BaseTransformer
*/
public function getClientId($name)
{
$client = $this->company
->clients()
$client = Client::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $name)),
@ -207,8 +208,7 @@ class BaseTransformer
*/
public function getProduct($key)
{
$product = $this->company
->products()
$product = Product::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`product_key`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $key)),
@ -225,8 +225,7 @@ class BaseTransformer
*/
public function getContact($email)
{
$contact = $this->company
->client_contacts()
$contact = ClientContact::where('company_id', $this->company->id)
->whereRaw("LOWER(REPLACE(`email`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $email)),
])
@ -278,8 +277,7 @@ class BaseTransformer
{
$name = strtolower(trim($name));
$tax_rate = $this->company
->tax_rates()
$tax_rate = TaxRate::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $name)),
@ -298,8 +296,7 @@ class BaseTransformer
{
$name = strtolower(trim($name));
$tax_rate = $this->company
->tax_rates()
$tax_rate = TaxRate::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $name)),
@ -348,8 +345,7 @@ class BaseTransformer
*/
public function getInvoiceId($invoice_number)
{
$invoice = $this->company
->invoices()
$invoice = Invoice::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`number`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $invoice_number)),
@ -366,8 +362,7 @@ class BaseTransformer
*/
public function hasInvoice($invoice_number)
{
return $this->company
->invoices()
return Invoice::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`number`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $invoice_number)),
@ -380,8 +375,7 @@ class BaseTransformer
*/
public function hasExpense($expense_number)
{
return $this->company
->expenses()
return Expense::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`number`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $expense_number)),
@ -396,8 +390,7 @@ class BaseTransformer
*/
public function hasQuote($quote_number)
{
return $this->company
->quotes()
return Quote::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`number`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $quote_number)),
@ -412,8 +405,7 @@ class BaseTransformer
*/
public function getInvoiceClientId($invoice_number)
{
$invoice = $this->company
->invoices()
$invoice = Invoice::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`number`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $invoice_number)),
@ -430,8 +422,7 @@ class BaseTransformer
*/
public function getVendorId($name)
{
$vendor = $this->company
->vendors()
$vendor = Vendor::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $name)),
@ -467,8 +458,7 @@ class BaseTransformer
*/
public function getExpenseCategoryId($name)
{
$ec = $this->company
->expense_categories()
$ec = ExpenseCategory::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $name)),
@ -504,8 +494,7 @@ class BaseTransformer
*/
public function getProjectId($name, $clientId = null)
{
$project = $this->company
->projects()
$project = Project::where('company_id', $this->company->id)
->where('is_deleted', false)
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
strtolower(str_replace(' ', '', $name)),

View File

@ -52,15 +52,42 @@ class VendorTransformer extends BaseTransformer
'custom_value2' => $this->getString($data, 'vendor.custom_value2'),
'custom_value3' => $this->getString($data, 'vendor.custom_value3'),
'custom_value4' => $this->getString($data, 'vendor.custom_value4'),
'vendor_contacts' => [
// 'vendor_contacts' => [
// [
// 'first_name' => $this->getString(
// $data,
// 'vendor.first_name'
// ),
// 'last_name' => $this->getString($data, 'vendor.last_name'),
// 'email' => $this->getString($data, 'vendor.email'),
// 'phone' => $this->getString($data, 'vendor.phone'),
// ],
// ],
'contacts' => [
[
'first_name' => $this->getString(
$data,
'vendor.first_name'
'contact.first_name'
),
'last_name' => $this->getString($data, 'contact.last_name'),
'email' => $this->getString($data, 'contact.email'),
'phone' => $this->getString($data, 'contact.phone'),
'custom_value1' => $this->getString(
$data,
'contact.custom_value1'
),
'custom_value2' => $this->getString(
$data,
'contact.custom_value2'
),
'custom_value3' => $this->getString(
$data,
'contact.custom_value3'
),
'custom_value4' => $this->getString(
$data,
'contact.custom_value4'
),
'last_name' => $this->getString($data, 'vendor.last_name'),
'email' => $this->getString($data, 'vendor.email'),
'phone' => $this->getString($data, 'vendor.phone'),
],
],
'country_id' => isset($data['vendor.country_id'])

View File

@ -44,12 +44,12 @@ class RecurringInvoicesCron
nlog('Sending recurring invoices '.$start);
if (! config('ninja.db.multi_db_enabled')) {
$recurring_invoices = RecurringInvoice::where('next_send_date', '<=', now()->toDateTimeString())
$recurring_invoices = RecurringInvoice::where('status_id', RecurringInvoice::STATUS_ACTIVE)
->where('is_deleted', false)
->where('remaining_cycles', '!=', '0')
->whereNotNull('next_send_date')
->whereNull('deleted_at')
->where('is_deleted', false)
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
->where('remaining_cycles', '!=', '0')
->where('next_send_date', '<=', now()->toDateTimeString())
->whereHas('client', function ($query) {
$query->where('is_deleted', 0)
->where('deleted_at', null);
@ -84,12 +84,12 @@ class RecurringInvoicesCron
foreach (MultiDB::$dbs as $db) {
MultiDB::setDB($db);
$recurring_invoices = RecurringInvoice::where('next_send_date', '<=', now()->toDateTimeString())
->whereNotNull('next_send_date')
->whereNull('deleted_at')
$recurring_invoices = RecurringInvoice::where('status_id', RecurringInvoice::STATUS_ACTIVE)
->where('is_deleted', false)
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
->where('remaining_cycles', '!=', '0')
->whereNull('deleted_at')
->whereNotNull('next_send_date')
->where('next_send_date', '<=', now()->toDateTimeString())
->whereHas('client', function ($query) {
$query->where('is_deleted', 0)
->where('deleted_at', null);

View File

@ -74,7 +74,7 @@ class CSVIngest implements ShouldQueue
$engine = $this->bootEngine();
foreach (['client', 'product', 'invoice', 'payment', 'vendor', 'expense'] as $entity) {
foreach (['client', 'product', 'invoice', 'payment', 'vendor', 'expense', 'quote'] as $entity) {
$engine->import($entity);
}

View File

@ -354,14 +354,19 @@ class NinjaMailerJob implements ShouldQueue
if(!str_contains($this->nmo->to_user->email, "@"))
return true;
/* On the hosted platform if the user has not verified their account we fail here - but still check what they are trying to send! */
if(Ninja::isHosted() && $this->company->account && !$this->company->account->account_sms_verified){
if(class_exists(\Modules\Admin\Jobs\Account\EmailQuality::class))
return (new \Modules\Admin\Jobs\Account\EmailQuality($this->nmo, $this->company))->run();
return true;
}
/* On the hosted platform we actively scan all outbound emails to ensure outbound email quality remains high */
if(class_exists(\Modules\Admin\Jobs\Account\EmailQuality::class))
return (new \Modules\Admin\Jobs\Account\EmailQuality($this->nmo, $this->company))->run();
/* On the hosted platform if the user has not verified their account we fail here */
if(Ninja::isHosted() && $this->company->account && !$this->company->account->account_sms_verified)
return true;
return false;
}

View File

@ -60,11 +60,11 @@ class ReminderJob implements ShouldQueue
{
nlog('Sending invoice reminders '.now()->format('Y-m-d h:i:s'));
Invoice::where('next_send_date', '<=', now()->toDateTimeString())
->whereNull('deleted_at')
->where('is_deleted', 0)
Invoice::where('is_deleted', 0)
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
->whereNull('deleted_at')
->where('balance', '>', 0)
->where('next_send_date', '<=', now()->toDateTimeString())
->whereHas('client', function ($query) {
$query->where('is_deleted', 0)
->where('deleted_at', null);

View File

@ -222,6 +222,7 @@ class PaymentEmailEngine extends BaseEmailEngine
$data['$view_link'] = ['value' => '<a class="button" href="'.$this->payment->getLink().'">'.ctrans('texts.view_payment').'</a>', 'label' => ctrans('texts.view_payment')];
$data['$view_button'] = &$data['$view_link'];
$data['$viewButton'] = &$data['$view_link'];
$data['$viewLink'] = &$data['$view_link'];
$data['$paymentLink'] = &$data['$view_link'];
$data['$portalButton'] = ['value' => "<a href='{$this->payment->getPortalLink()}'>".ctrans('texts.login').'</a>', 'label' =>''];
@ -237,6 +238,10 @@ class PaymentEmailEngine extends BaseEmailEngine
$data['$invoice.po_number'] = ['value' => $this->formatPoNumber(), 'label' => ctrans('texts.po_number')];
$data['$poNumber'] = &$data['$invoice.po_number'];
$data['$payment.status'] = ['value' => $this->payment->stringStatus($this->payment->status_id), 'label' => ctrans('texts.payment_status')];
$data['$invoices.amount'] = ['value' => $this->formatInvoiceField('amount'), 'label' => ctrans('texts.invoices')];
$data['$invoices.balance'] = ['value' => $this->formatInvoiceField('balance'), 'label' => ctrans('texts.invoices')];
$data['$invoices.due_date'] = ['value' => $this->formatInvoiceField('due_date'), 'label' => ctrans('texts.invoices')];
$data['$invoices.po_number'] = ['value' => $this->formatInvoiceField('po_number'), 'label' => ctrans('texts.invoices')];
$arrKeysLength = array_map('strlen', array_keys($data));
array_multisort($arrKeysLength, SORT_DESC, $data);
@ -244,6 +249,22 @@ class PaymentEmailEngine extends BaseEmailEngine
return $data;
}
private function formatInvoiceField($field)
{
$invoice = '';
foreach ($this->payment->invoices as $invoice) {
$invoice_field = $invoice->{$field};
$invoice .= ctrans('texts.invoice_number_short') . "{$invoice->number} {$invoice_field}";
}
return $invoice;
}
private function formatInvoice()
{
$invoice = '';
@ -282,11 +303,15 @@ class PaymentEmailEngine extends BaseEmailEngine
$invoice_list = '<br><br>';
foreach ($this->payment->invoices as $invoice) {
$invoice_list .= ctrans('texts.po_number')." {$invoice->po_number} <br>";
if(strlen($invoice->po_number) > 1)
$invoice_list .= ctrans('texts.po_number')." {$invoice->po_number} <br>";
$invoice_list .= ctrans('texts.invoice_number_short')." {$invoice->number} <br>";
$invoice_list .= ctrans('texts.invoice_amount').' '.Number::formatMoney($invoice->pivot->amount, $this->client).'<br>';
$invoice_list .= ctrans('texts.invoice_balance').' '.Number::formatMoney($invoice->fresh()->balance, $this->client).'<br>';
$invoice_list .= '-----<br>';
}
return $invoice_list;

View File

@ -266,6 +266,11 @@ class Activity extends StaticModel
return $this->belongsTo(Invoice::class)->withTrashed();
}
public function vendor()
{
return $this->belongsTo(Vendor::class)->withTrashed();
}
/**
* @return mixed
*/

View File

@ -24,9 +24,6 @@ class UserObserver
public function created(User $user)
{
if(class_exists(\Modules\Admin\Jobs\Account\UserQuality::class))
\Modules\Admin\Jobs\Account\UserQuality::dispatch($user, $user->account->key);
}
/**
@ -38,9 +35,6 @@ class UserObserver
public function updated(User $user)
{
if(class_exists(\Modules\Admin\Jobs\Account\UserQuality::class))
\Modules\Admin\Jobs\Account\UserQuality::dispatch($user, $user->account->key);
}
/**

View File

@ -131,7 +131,8 @@ class PaymentRepository extends BaseRepository {
/*Ensure payment number generated*/
if (! $payment->number || strlen($payment->number) == 0) {
$payment->number = $payment->client->getNextPaymentNumber($payment->client, $payment);
// $payment->number = $payment->client->getNextPaymentNumber($payment->client, $payment);
$payment->service()->applyNumber();
}
/*Set local total variables*/

View File

@ -62,7 +62,9 @@ class UserRepository extends BaseRepository
// $account->num_users++;
// $account->save();
// }
if(array_key_exists('oauth_provider_id', $details))
unset($details['oauth_provider_id']);
$user->fill($details);
//allow users to change only their passwords - not others!

View File

@ -41,20 +41,37 @@ class MarkPaid extends AbstractService
public function run()
{
if ($this->invoice->status_id == Invoice::STATUS_DRAFT) {
$this->invoice->service()->markSent()->save();
}
/*Don't double pay*/
if ($this->invoice->status_id == Invoice::STATUS_PAID) {
return $this->invoice;
}
if ($this->invoice->status_id == Invoice::STATUS_DRAFT) {
$this->invoice->service()->markSent()->save();
}
$payable_balance = $this->invoice->balance;
\DB::connection(config('database.default'))->transaction(function () use($payable_balance) {
$this->invoice = Invoice::where('id', $this->invoice->id)->lockForUpdate()->first();
$this->invoice
->service()
->setExchangeRate()
->updateBalance($payable_balance * -1)
->updatePaidToDate($payable_balance)
->setStatus(Invoice::STATUS_PAID)
->save();
}, 1);
/* Create Payment */
$payment = PaymentFactory::create($this->invoice->company_id, $this->invoice->user_id);
$payment->amount = $this->invoice->balance;
$payment->applied = $this->invoice->balance;
$payment->amount = $payable_balance;
$payment->applied = $payable_balance;
$payment->status_id = Payment::STATUS_COMPLETED;
$payment->client_id = $this->invoice->client_id;
$payment->transaction_reference = ctrans('texts.manual_entry');
@ -79,20 +96,20 @@ class MarkPaid extends AbstractService
/* Create a payment relationship to the invoice entity */
$payment->invoices()->attach($this->invoice->id, [
'amount' => $payment->amount,
'amount' => $payable_balance,
]);
event('eloquent.created: App\Models\Payment', $payment);
$this->invoice->next_send_date = null;
$this->invoice
->service()
->setExchangeRate()
->updateBalance($payment->amount * -1)
->updatePaidToDate($payment->amount)
->setStatus(Invoice::STATUS_PAID)
->save();
// $this->invoice
// ->service()
// ->setExchangeRate()
// ->updateBalance($payment->amount * -1)
// ->updatePaidToDate($payment->amount)
// ->setStatus(Invoice::STATUS_PAID)
// ->save();
$this->invoice
->service()
@ -101,7 +118,7 @@ class MarkPaid extends AbstractService
->save();
$payment->ledger()
->updatePaymentBalance($payment->amount * -1);
->updatePaymentBalance($payable_balance * -1);
\DB::connection(config('database.default'))->transaction(function () use ($payment) {

View File

@ -42,9 +42,9 @@ class ZeroCostProduct extends AbstractService
$invoice = $this->subscription->service()->createInvoice($this->data);
$invoice->service()
->markPaid()
->save();
$invoice = $invoice->service()
->markPaid()
->save();
$redirect_url = "/client/invoices/{$invoice->hashed_id}";

View File

@ -184,6 +184,9 @@ class SystemHealth
private static function checkPhpCli()
{
if(!function_exists('exec'))
return "Unable to check CLI version";
try {
exec('php -v', $foo, $exitCode);

View File

@ -408,6 +408,68 @@ class VendorHtmlEngine
$data['$payments'] = ['value' => '', 'label' => ctrans('texts.payments')];
if($this->entity->client()->exists())
{
$data['$client1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'client1', $this->entity->client->custom_value1, $this->entity->client) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'client1')];
$data['$client2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'client2', $this->entity->client->custom_value2, $this->entity->client) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'client2')];
$data['$client3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'client3', $this->entity->client->custom_value3, $this->entity->client) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'client3')];
$data['$client4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'client4', $this->entity->client->custom_value4, $this->entity->client) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'client4')];
$data['$client.custom1'] = &$data['$client1'];
$data['$client.custom2'] = &$data['$client2'];
$data['$client.custom3'] = &$data['$client3'];
$data['$client.custom4'] = &$data['$client4'];
$data['$client.number'] = ['value' => $this->entity->client->number ?: '&nbsp;', 'label' => ctrans('texts.number')];
$data['$client_name'] = ['value' => $this->entity->client->present()->name() ?: '&nbsp;', 'label' => ctrans('texts.client_name')];
$data['$client.name'] = &$data['$client_name'];
$data['$client'] = &$data['$client_name'];
$data['$client.address1'] = &$data['$address1'];
$data['$client.address2'] = &$data['$address2'];
$data['$client_address'] = ['value' => $this->entity->client->present()->address() ?: '&nbsp;', 'label' => ctrans('texts.address')];
$data['$client.address'] = &$data['$client_address'];
$data['$client.postal_code'] = ['value' => $this->entity->client->postal_code ?: '&nbsp;', 'label' => ctrans('texts.postal_code')];
$data['$client.public_notes'] = ['value' => $this->entity->client->public_notes ?: '&nbsp;', 'label' => ctrans('texts.notes')];
$data['$client.city'] = ['value' => $this->entity->client->city ?: '&nbsp;', 'label' => ctrans('texts.city')];
$data['$client.state'] = ['value' => $this->entity->client->state ?: '&nbsp;', 'label' => ctrans('texts.state')];
$data['$client.id_number'] = &$data['$id_number'];
$data['$client.vat_number'] = &$data['$vat_number'];
$data['$client.website'] = &$data['$website'];
$data['$client.phone'] = &$data['$phone'];
$data['$city_state_postal'] = ['value' => $this->entity->client->present()->cityStateZip($this->entity->client->city, $this->entity->client->state, $this->entity->client->postal_code, false) ?: '&nbsp;', 'label' => ctrans('texts.city_state_postal')];
$data['$client.city_state_postal'] = &$data['$city_state_postal'];
$data['$postal_city_state'] = ['value' => $this->entity->client->present()->cityStateZip($this->entity->client->city, $this->entity->client->state, $this->entity->client->postal_code, true) ?: '&nbsp;', 'label' => ctrans('texts.postal_city_state')];
$data['$client.postal_city_state'] = &$data['$postal_city_state'];
$data['$client.country'] = &$data['$country'];
$data['$client.email'] = &$data['$email'];
$data['$client.billing_address'] = &$data['$client_address'];
$data['$client.billing_address1'] = &$data['$client.address1'];
$data['$client.billing_address2'] = &$data['$client.address2'];
$data['$client.billing_city'] = &$data['$client.city'];
$data['$client.billing_state'] = &$data['$client.state'];
$data['$client.billing_postal_code'] = &$data['$client.postal_code'];
$data['$client.billing_country'] = &$data['$client.country'];
$data['$client.shipping_address'] = ['value' => $this->entity->client->present()->shipping_address() ?: '&nbsp;', 'label' => ctrans('texts.shipping_address')];
$data['$client.shipping_address1'] = ['value' => $this->entity->client->shipping_address1 ?: '&nbsp;', 'label' => ctrans('texts.shipping_address1')];
$data['$client.shipping_address2'] = ['value' => $this->entity->client->shipping_address2 ?: '&nbsp;', 'label' => ctrans('texts.shipping_address2')];
$data['$client.shipping_city'] = ['value' => $this->entity->client->shipping_city ?: '&nbsp;', 'label' => ctrans('texts.shipping_city')];
$data['$client.shipping_state'] = ['value' => $this->entity->client->shipping_state ?: '&nbsp;', 'label' => ctrans('texts.shipping_state')];
$data['$client.shipping_postal_code'] = ['value' => $this->entity->client->shipping_postal_code ?: '&nbsp;', 'label' => ctrans('texts.shipping_postal_code')];
$data['$client.shipping_country'] = ['value' => isset($this->entity->client->shipping_country->name) ? ctrans('texts.country_' . $this->entity->client->shipping_country->name) : '', 'label' => ctrans('texts.shipping_country')];
$data['$client.currency'] = ['value' => $this->entity->client->currency()->code, 'label' => ''];
$data['$client.lang_2'] = ['value' => optional($this->entity->client->language())->locale, 'label' => ''];
$data['$client.balance'] = ['value' => Number::formatMoney($this->entity->client->balance, $this->entity->client), 'label' => ctrans('texts.account_balance')];
$data['$client_balance'] = ['value' => Number::formatMoney($this->entity->client->balance, $this->entity->client), 'label' => ctrans('texts.account_balance')];
}
$arrKeysLength = array_map('strlen', array_keys($data));
array_multisort($arrKeysLength, SORT_DESC, $data);

View File

@ -14,8 +14,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => '5.5.17',
'app_tag' => '5.5.17',
'app_version' => '5.5.18',
'app_tag' => '5.5.18',
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''),

View File

@ -0,0 +1,43 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('payments', function (Blueprint $table) {
$table->index(['transaction_reference']);
});
Schema::table('paymentables', function (Blueprint $table) {
$table->index(['paymentable_id']);
});
Schema::table('invoices', function (Blueprint $table) {
$table->index(['recurring_id']);
$table->index(['status_id','balance']);
});
Schema::table('quotes', function (Blueprint $table) {
$table->index(['company_id','updated_at']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
}
};

View File

@ -800,7 +800,7 @@ $LANG = array(
'activity_51' => ':user deleted user :user',
'activity_52' => ':user restored user :user',
'activity_53' => ':user marked sent :invoice',
'activity_54' => ':user reopened ticket :ticket',
'activity_54' => ':user paid invoice :invoice',
'activity_55' => ':contact replied ticket :ticket',
'activity_56' => ':user viewed ticket :ticket',

View File

@ -7,7 +7,7 @@ const RESOURCES = {
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
"canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd",
"canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba",
"main.dart.js": "3234746bf3c8a3ccec3cf901969c352c",
"main.dart.js": "d55f18d67504e30a0afcd79c2681fc4b",
"favicon.ico": "51636d3a390451561744c42188ccd628",
"assets/AssetManifest.json": "759f9ef9973f7e26c2a51450b55bb9fa",
"assets/assets/google_fonts/Roboto-Regular.ttf": "8a36205bd9b83e03af0591a004bc97f4",
@ -295,7 +295,7 @@ const RESOURCES = {
"assets/FontManifest.json": "087fb858dc3cbfbf6baf6a30004922f1",
"assets/NOTICES": "254a5bf1eeb00601955e148b31cb925c",
"flutter.js": "eb2682e33f25cd8f1fc59011497c35f8",
"/": "48872e415511ff066e9403545e4ba572",
"/": "acca806f9c3bee9e5e9560598f7376de",
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
"version.json": "9eca00898047311eda7456072e79d77d",
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",

View File

@ -0,0 +1,3 @@
<svg width="598" height="450" viewBox="0 0 598 450" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.05" d="M474.826 149.58C537.96 127.127 603.054 7.0443 592.708 -44.907L-72.3135 -6.27372L-93.116 541.526C-51.621 532.17 19.6183 527.658 70.9927 465.58C155.706 363.219 239.064 427.938 284.962 383.031C330.859 338.124 315.01 295.858 330.529 241.045C346.048 186.232 395.909 177.647 474.826 149.58Z" fill="white" stroke="white" stroke-width="7"/>
</svg>

After

Width:  |  Height:  |  Size: 464 B

View File

@ -0,0 +1,3 @@
<svg width="595" height="450" viewBox="0 0 595 450" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.2" d="M474.942 153.487C538.076 131.034 603.17 10.9513 592.823 -41L-72.1976 -2.36674L-93 545.433C-51.505 536.077 19.7343 531.565 71.1087 469.487C155.822 367.126 239.18 431.845 285.078 386.938C330.975 342.031 315.126 299.765 330.645 244.952C346.164 190.139 396.025 181.554 474.942 153.487Z" stroke="white"/>
</svg>

After

Width:  |  Height:  |  Size: 430 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 127 KiB

View File

@ -0,0 +1,3 @@
<svg width="598" height="450" viewBox="0 0 598 450" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.05" d="M474.826 149.58C537.96 127.127 603.054 7.0443 592.708 -44.907L-72.3135 -6.27372L-93.116 541.526C-51.621 532.17 19.6183 527.658 70.9927 465.58C155.706 363.219 239.064 427.938 284.962 383.031C330.859 338.124 315.01 295.858 330.529 241.045C346.048 186.232 395.909 177.647 474.826 149.58Z" fill="white" stroke="white" stroke-width="7"/>
</svg>

After

Width:  |  Height:  |  Size: 464 B

186052
public/main.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

186162
public/main.foss.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"/livewire.js":"/livewire.js?id=c69d0f2801c01fcf8166"}
{"/livewire.js":"/livewire.js?id=de3fca26689cb5a39af4"}

View File

@ -125,7 +125,7 @@
<img src="{{ $logo ?? '' }}" alt="" width="155" border="0" align="middle" style="display:block;" />
<div style="mso-hide:all;">
<![endif]-->
<img class="logo-light" src="{{ $logo ?? '' }}" alt="" width="400" style="margin-top: 10px; max-width: 570px; display: block; margin-left: auto; margin-right: auto;"/>
<img class="logo-light" src="{{ $logo ?? '' }}" alt="" width="400" style="margin-top: 10px; max-width: 200px; display: block; margin-left: auto; margin-right: auto;"/>
<!--[if gte mso 9]>
</div>
<![endif]-->

View File

@ -104,14 +104,13 @@
</tr>
<tr>
<td align="center" cellpadding="20">
<div
style="border: 1px solid #c2c2c2; border-bottom: none; padding-bottom: 10px; border-top-left-radius: 3px; border-top-right-radius: 3px;">
<div style="border: 1px solid #c2c2c2; border-bottom: none; padding-bottom: 10px; border-top-left-radius: 3px; border-top-right-radius: 3px;">
<!--[if gte mso 9]>
<img src="{{ $logo ?? '' }}" alt="" width="400" border="0" align="middle" style="display:block;" />
<div style="mso-hide:all;">
<![endif]-->
<img src="{{ $logo ?? '' }}" alt="" width="400" style="margin-top: 40px; max-width: 155px; display: block; margin-left: auto; margin-right: auto;"/>
<img src="{{ $logo ?? '' }}" alt="" width="400" style="margin-top: 40px; max-width: 200px; display: block; margin-left: auto; margin-right: auto;"/>
<!--[if gte mso 9]>
</div>
<![endif]-->

File diff suppressed because it is too large Load Diff

View File

@ -72,7 +72,7 @@ class EntityPaidToDateTest extends TestCase
$this->assertEquals($invoice->balance, 20);
$invoice->service()->markPaid()->save();
$invoice = $invoice->service()->markPaid()->save();
$this->assertEquals($invoice->paid_to_date, 20);
}
@ -81,7 +81,7 @@ class EntityPaidToDateTest extends TestCase
{
$invoice = $this->bootNewInvoice();
$invoice->service()->markPaid()->save();
$invoice = $invoice->service()->markPaid()->save();
$this->assertEquals(20, $invoice->paid_to_date);

View File

@ -1,24 +1,24 @@
"Invoice Ninja v4.5.17 - December 19, 2020 11:28 pm","","","","","","","","","","","","","","","","","","","","","","","","",""
"","","","","","","","","","","","","","","","","","","","","","","","","",""
"Vendors","","","","","","","","","","","","","","","","","","","","","","","","",""
"Name","Balance","Paid to Date","Billing Street","Billing Apt/Suite","Billing City","Billing State/Province","Billing Postal Code","Billing Country","Shipping Street","Shipping Apt/Suite","Shipping City","Shipping State/Province","Shipping Postal Code","Shipping Country","ID Number","VAT Number","Website","Phone","Currency","Public Notes","Private Notes","First Name","Last Name","Email","Phone"
"Ludwig Krajcik DVM","$-142.85","$205.15","371 O'Connell Summit","Suite 612","Lornamouth","New York","83425-0771","","","","","","","","","","","","","","","Terrill","Ondricka","brook59@example.org","1-537-759-0369"
"Bradly Jaskolski Sr.","$310.81","$313.71","21854 Prosacco Isle","Suite 619","Vicentastad","Colorado","05144","","","","","","","","","","","","","","","Pink","Balistreri","gheidenreich@example.org","1-995-790-2394 x58884"
"Mr. Dustin Stehr I","$285.70","$250.97","2941 Terence Station","Apt. 761","Bernierbury","Massachusetts","47675","","","","","","","","","","","","","","","Shemar","Stehr","labadie.dominique@example.com","624-610-5940"
"Dr. Baron Armstrong Sr.","$241.53","$280.42","9469 Ofelia Gateway","Suite 748","Evelynside","New Hampshire","66872","","","","","","","","","","","","","","","Fabiola","Mitchell","nico78@example.net","1-986-772-8058 x00345"
"Dr. Clemens Douglas MD","$317.94","$342.92","2919 Thompson Common Suite 410","Suite 381","Port Margie","Nevada","49890","","","","","","","","","","","","","","","Lolita","Tremblay","daphney.marquardt@example.com","1-461-699-9192 x9875"
"Dr. Claire Huel Sr.","$333.45","$359.51","363 Arlene Causeway Suite 763","Suite 409","Millerstad","Florida","25750","","","","","","","","","","","","","","","Brown","Lakin","vbeer@example.net","(776) 821-0650 x839"
"Francisca Padberg","$366.58","$203.16","5558 Ratke Flats","Suite 511","Krystelport","Alabama","15359-3783","","","","","","","","","","","","","","","Hallie","Dooley","kgottlieb@example.net","1-573-770-4753 x72129"
"Dr. Roy Kihn","$272.12","$251.41","20236 O'Hara Shores","Suite 368","Aliciaport","North Carolina","35415","","","","","","","","","","","","","","","Elwyn","Daugherty","wunsch.rozella@example.org","(745) 859-5855 x04216"
"Nasir Vandervort","$401.23","$173.17","24599 Hills Centers Suite 467","Apt. 038","North German","Ohio","85363-4720","","","","","","","","","","","","","","","Tre","Moore","wilfrid.kuhic@example.com","1-519-675-7395"
"Garry Rosenbaum","$271.82","$306.63","7127 Heidenreich Union Apt. 168","Suite 441","North Murray","North Carolina","29242","","","","","","","","","","","","","","","Ricardo","Johnston","ddubuque@example.com","(682) 216-1962"
"Hildegard Crona PhD","$398.96","$162.49","60142 Janice Islands","Apt. 627","South Stantown","Colorado","10298-5737","","","","","","","","","","","","","","","Miles","Tremblay","sabrina86@example.org","775-210-8656 x93138"
"Kristopher White I","$318.14","$423.20","7498 Brook Crest Apt. 175","Suite 682","Marianoland","Connecticut","86235-9979","","","","","","","","","","","","","","","Mateo","Welch","jedidiah64@example.com","847.353.7644"
"Ethan Grant","$380.71","$367.38","26755 June Extension Suite 589","Suite 706","North Krystelmouth","Delaware","12414","","","","","","","","","","","","","","","Colton","Muller","dorian.mayert@example.net","(267) 647-0537"
"Terry Shields","$230.25","$290.83","60946 Kayden Camp Apt. 046","Apt. 178","Douglashaven","Wyoming","68992","","","","","","","","","","","","","","","Dashawn","Homenick","hills.gina@example.net","(478) 814-9961"
"Agustina Lockman","$351.60","$264.81","152 Pattie Coves","Suite 971","North Mohamed","Hawaii","52966","","","","","","","","","","","","","","","Bert","Fritsch","greilly@example.org","15342929833"
"Alfonso Schimmel","$343.71","$200.99","358 Hills Coves","Apt. 032","Lake Aisha","District of Columbia","68945-0439","","","","","","","","","","","","","","","Antonio","Hayes","dkshlerin@example.com","1-350-691-4459 x775"
"Vergie Monahan","$210.27","$201.10","64004 Anderson Mall Suite 207","Suite 469","Oleshire","California","78369","","","","","","","","","","","","","","","Hilario","Morissette","zjacobs@example.net","552.914.6800 x81120"
"Carol Cremin","$301.53","$473.39","68731 Bartoletti Crescent","Suite 855","Aaronland","Wyoming","07924","","","","","","","","","","","","","","","Nathen","Wehner","jacobi.rosendo@example.com","1-223-910-2060 x09970"
"Randal Bosco MD","$318.71","$226.47","51884 Peter Falls","Suite 314","Angelicaville","Nebraska","78016-3254","","","","","","","","","","","","","","","Angelo","Ward","kozey.aurelio@example.org","1-329-488-8800"
"Ms. Alena Cassin","$262.45","$388.50","706 Delfina Burgs","Apt. 996","Bertaton","Ohio","22957","","","","","","","","","","","","","","","Eusebio","Reinger","golden.green@example.org","429-551-1362"
"Invoice Ninja v4.5.17 - December 19, 2020 11:28 pm",,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,
Vendors,,,,,,,,,,,,,,,,,,,,,,,,,
Name,Balance,Paid to Date,Billing Street,Billing Apt/Suite,Billing City,Billing State/Province,Billing Postal Code,Billing Country,Shipping Street,Shipping Apt/Suite,Shipping City,Shipping State/Province,Shipping Postal Code,Shipping Country,ID Number,VAT Number,Website,Phone,Currency,Public Notes,Private Notes,First Name,Last Name,Email,Phone
Ludwig Krajcik DVM,$-142.85,$205.15,371 O'Connell Summit,Suite 612,Lornamouth,New York,83425-0771,Australia,,,,,,,,,,,,,,Terrill,Ondricka,brook59@example.org,1-537-759-0369
Bradly Jaskolski Sr.,$310.81,$313.71,21854 Prosacco Isle,Suite 619,Vicentastad,Colorado,5144,Germany,,,,,,,,,,,,,,Pink,Balistreri,gheidenreich@example.org,1-995-790-2394 x58884
Mr. Dustin Stehr I,$285.70,$250.97,2941 Terence Station,Apt. 761,Bernierbury,Massachusetts,47675,USA,,,,,,,,,,,,,,Shemar,Stehr,labadie.dominique@example.com,624-610-5940
Dr. Baron Armstrong Sr.,$241.53,$280.42,9469 Ofelia Gateway,Suite 748,Evelynside,New Hampshire,66872,1,,,,,,,,,,,,,,Fabiola,Mitchell,nico78@example.net,1-986-772-8058 x00345
Dr. Clemens Douglas MD,$317.94,$342.92,2919 Thompson Common Suite 410,Suite 381,Port Margie,Nevada,49890,,,,,,,,,,,,,,,Lolita,Tremblay,daphney.marquardt@example.com,1-461-699-9192 x9875
Dr. Claire Huel Sr.,$333.45,$359.51,363 Arlene Causeway Suite 763,Suite 409,Millerstad,Florida,25750,,,,,,,,,,,,,,,Brown,Lakin,vbeer@example.net,(776) 821-0650 x839
Francisca Padberg,$366.58,$203.16,5558 Ratke Flats,Suite 511,Krystelport,Alabama,15359-3783,,,,,,,,,,,,,,,Hallie,Dooley,kgottlieb@example.net,1-573-770-4753 x72129
Dr. Roy Kihn,$272.12,$251.41,20236 O'Hara Shores,Suite 368,Aliciaport,North Carolina,35415,,,,,,,,,,,,,,,Elwyn,Daugherty,wunsch.rozella@example.org,(745) 859-5855 x04216
Nasir Vandervort,$401.23,$173.17,24599 Hills Centers Suite 467,Apt. 038,North German,Ohio,85363-4720,,,,,,,,,,,,,,,Tre,Moore,wilfrid.kuhic@example.com,1-519-675-7395
Garry Rosenbaum,$271.82,$306.63,7127 Heidenreich Union Apt. 168,Suite 441,North Murray,North Carolina,29242,,,,,,,,,,,,,,,Ricardo,Johnston,ddubuque@example.com,(682) 216-1962
Hildegard Crona PhD,$398.96,$162.49,60142 Janice Islands,Apt. 627,South Stantown,Colorado,10298-5737,,,,,,,,,,,,,,,Miles,Tremblay,sabrina86@example.org,775-210-8656 x93138
Kristopher White I,$318.14,$423.20,7498 Brook Crest Apt. 175,Suite 682,Marianoland,Connecticut,86235-9979,,,,,,,,,,,,,,,Mateo,Welch,jedidiah64@example.com,847.353.7644
Ethan Grant,$380.71,$367.38,26755 June Extension Suite 589,Suite 706,North Krystelmouth,Delaware,12414,,,,,,,,,,,,,,,Colton,Muller,dorian.mayert@example.net,(267) 647-0537
Terry Shields,$230.25,$290.83,60946 Kayden Camp Apt. 046,Apt. 178,Douglashaven,Wyoming,68992,,,,,,,,,,,,,,,Dashawn,Homenick,hills.gina@example.net,(478) 814-9961
Agustina Lockman,$351.60,$264.81,152 Pattie Coves,Suite 971,North Mohamed,Hawaii,52966,,,,,,,,,,,,,,,Bert,Fritsch,greilly@example.org,15342929833
Alfonso Schimmel,$343.71,$200.99,358 Hills Coves,Apt. 032,Lake Aisha,District of Columbia,68945-0439,,,,,,,,,,,,,,,Antonio,Hayes,dkshlerin@example.com,1-350-691-4459 x775
Vergie Monahan,$210.27,$201.10,64004 Anderson Mall Suite 207,Suite 469,Oleshire,California,78369,,,,,,,,,,,,,,,Hilario,Morissette,zjacobs@example.net,552.914.6800 x81120
Carol Cremin,$301.53,$473.39,68731 Bartoletti Crescent,Suite 855,Aaronland,Wyoming,7924,,,,,,,,,,,,,,,Nathen,Wehner,jacobi.rosendo@example.com,1-223-910-2060 x09970
Randal Bosco MD,$318.71,$226.47,51884 Peter Falls,Suite 314,Angelicaville,Nebraska,78016-3254,,,,,,,,,,,,,,,Angelo,Ward,kozey.aurelio@example.org,1-329-488-8800
Ms. Alena Cassin,$262.45,$388.50,706 Delfina Burgs,Apt. 996,Bertaton,Ohio,22957,,,,,,,,,,,,,,,Eusebio,Reinger,golden.green@example.org,429-551-1362

1 Invoice Ninja v4.5.17 - December 19, 2020 11:28 pm
2
3 Vendors
4 Name Balance Paid to Date Billing Street Billing Apt/Suite Billing City Billing State/Province Billing Postal Code Billing Country Shipping Street Shipping Apt/Suite Shipping City Shipping State/Province Shipping Postal Code Shipping Country ID Number VAT Number Website Phone Currency Public Notes Private Notes First Name Last Name Email Phone
5 Ludwig Krajcik DVM $-142.85 $205.15 371 O'Connell Summit Suite 612 Lornamouth New York 83425-0771 Australia Terrill Ondricka brook59@example.org 1-537-759-0369
6 Bradly Jaskolski Sr. $310.81 $313.71 21854 Prosacco Isle Suite 619 Vicentastad Colorado 05144 5144 Germany Pink Balistreri gheidenreich@example.org 1-995-790-2394 x58884
7 Mr. Dustin Stehr I $285.70 $250.97 2941 Terence Station Apt. 761 Bernierbury Massachusetts 47675 USA Shemar Stehr labadie.dominique@example.com 624-610-5940
8 Dr. Baron Armstrong Sr. $241.53 $280.42 9469 Ofelia Gateway Suite 748 Evelynside New Hampshire 66872 1 Fabiola Mitchell nico78@example.net 1-986-772-8058 x00345
9 Dr. Clemens Douglas MD $317.94 $342.92 2919 Thompson Common Suite 410 Suite 381 Port Margie Nevada 49890 Lolita Tremblay daphney.marquardt@example.com 1-461-699-9192 x9875
10 Dr. Claire Huel Sr. $333.45 $359.51 363 Arlene Causeway Suite 763 Suite 409 Millerstad Florida 25750 Brown Lakin vbeer@example.net (776) 821-0650 x839
11 Francisca Padberg $366.58 $203.16 5558 Ratke Flats Suite 511 Krystelport Alabama 15359-3783 Hallie Dooley kgottlieb@example.net 1-573-770-4753 x72129
12 Dr. Roy Kihn $272.12 $251.41 20236 O'Hara Shores Suite 368 Aliciaport North Carolina 35415 Elwyn Daugherty wunsch.rozella@example.org (745) 859-5855 x04216
13 Nasir Vandervort $401.23 $173.17 24599 Hills Centers Suite 467 Apt. 038 North German Ohio 85363-4720 Tre Moore wilfrid.kuhic@example.com 1-519-675-7395
14 Garry Rosenbaum $271.82 $306.63 7127 Heidenreich Union Apt. 168 Suite 441 North Murray North Carolina 29242 Ricardo Johnston ddubuque@example.com (682) 216-1962
15 Hildegard Crona PhD $398.96 $162.49 60142 Janice Islands Apt. 627 South Stantown Colorado 10298-5737 Miles Tremblay sabrina86@example.org 775-210-8656 x93138
16 Kristopher White I $318.14 $423.20 7498 Brook Crest Apt. 175 Suite 682 Marianoland Connecticut 86235-9979 Mateo Welch jedidiah64@example.com 847.353.7644
17 Ethan Grant $380.71 $367.38 26755 June Extension Suite 589 Suite 706 North Krystelmouth Delaware 12414 Colton Muller dorian.mayert@example.net (267) 647-0537
18 Terry Shields $230.25 $290.83 60946 Kayden Camp Apt. 046 Apt. 178 Douglashaven Wyoming 68992 Dashawn Homenick hills.gina@example.net (478) 814-9961
19 Agustina Lockman $351.60 $264.81 152 Pattie Coves Suite 971 North Mohamed Hawaii 52966 Bert Fritsch greilly@example.org 15342929833
20 Alfonso Schimmel $343.71 $200.99 358 Hills Coves Apt. 032 Lake Aisha District of Columbia 68945-0439 Antonio Hayes dkshlerin@example.com 1-350-691-4459 x775
21 Vergie Monahan $210.27 $201.10 64004 Anderson Mall Suite 207 Suite 469 Oleshire California 78369 Hilario Morissette zjacobs@example.net 552.914.6800 x81120
22 Carol Cremin $301.53 $473.39 68731 Bartoletti Crescent Suite 855 Aaronland Wyoming 07924 7924 Nathen Wehner jacobi.rosendo@example.com 1-223-910-2060 x09970
23 Randal Bosco MD $318.71 $226.47 51884 Peter Falls Suite 314 Angelicaville Nebraska 78016-3254 Angelo Ward kozey.aurelio@example.org 1-329-488-8800
24 Ms. Alena Cassin $262.45 $388.50 706 Delfina Burgs Apt. 996 Bertaton Ohio 22957 Eusebio Reinger golden.green@example.org 429-551-1362

View File

@ -185,7 +185,7 @@ class InvoiceAmountPaymentTest extends TestCase
$this->assertEquals(25, $invoice->balance);
$this->assertEquals(25, $invoice->amount);
$invoice->service()->markPaid()->save();
$invoice = $invoice->service()->markPaid()->save();
$invoice->fresh();

View File

@ -1422,7 +1422,7 @@ class PaymentTest extends TestCase
$this->assertEquals(10, $this->invoice->balance);
$this->assertEquals(10, $this->invoice->client->fresh()->balance);
$this->invoice->service()->markPaid()->save();
$this->invoice = $this->invoice->service()->markPaid()->save();
$this->assertEquals(0, $this->invoice->balance);
$this->assertEquals(0, $this->invoice->client->balance);

View File

@ -40,7 +40,7 @@ class GoogleAnalyticsTest extends TestCase
$invoice = $this->invoice;
$client = $this->client;
$invoice->service()->markPaid()->save();
$invoice = $invoice->service()->markPaid()->save();
$payment = $invoice->payments->first();

View File

@ -45,7 +45,7 @@ class InvoiceActionsTest extends TestCase
{
$this->withoutEvents();
$this->invoice->service()->markPaid()->save();
$this->invoice = $this->invoice->service()->markPaid()->save();
$this->assertFalse($this->invoiceDeletable($this->invoice));
$this->assertTrue($this->invoiceReversable($this->invoice));

View File

@ -82,7 +82,7 @@ class SubscriptionsCalcTest extends TestCase
$this->assertFalse($sub_calculator->isPaidUp());
$invoice->service()->markPaid()->save();
$invoice = $invoice->service()->markPaid()->save();
$this->assertTrue($sub_calculator->isPaidUp());