1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 21:22:58 +01:00

Merge pull request #7348 from turbo124/v5-develop

v5.3.78
This commit is contained in:
David Bomba 2022-03-31 08:12:07 +11:00 committed by GitHub
commit eaa73dd224
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 276 additions and 115 deletions

View File

@ -1 +1 @@
5.3.77
5.3.78

View File

@ -86,8 +86,6 @@ class HostedMigrations extends Command
$path = public_path('storage/migrations/import');
nlog(public_path('storage/migrations/import'));
$directory = new DirectoryIterator($path);
foreach ($directory as $file) {

View File

@ -80,8 +80,6 @@ class ImportMigrations extends Command
$path = $this->option('path') ?? public_path('storage/migrations/import');
nlog(public_path('storage/migrations/import'));
$directory = new DirectoryIterator($path);
foreach ($directory as $file) {

View File

@ -46,7 +46,6 @@ class BaseSettings
return is_null($value) ? '' : (string) $value;
case 'bool':
case 'boolean':
nlog($value);
return boolval($value);
case 'object':
return json_decode($value);

View File

@ -124,7 +124,7 @@ class Handler extends ExceptionHandler
}
});
if ($this->validException($exception) && auth()->guard('contact')->user()->company->account->report_errors) {
if ($this->validException($exception)) {
app('sentry')->captureException($exception);
}
}

View File

@ -54,10 +54,7 @@ class ProRata
{
$days = $from_date->copy()->diffInDays($to_date);
$days_in_frequency = $this->getDaysInFrequency($frequency);
nlog($from_date->format('Y-m-d'));
nlog($days);
nlog($days_in_frequency);
nlog($amount);
return round( (($days/$days_in_frequency) * $amount),2);
}

View File

@ -276,6 +276,7 @@ class RecurringExpenseController extends BaseController
}
$recurring_expense = $this->recurring_expense_repo->save($request->all(), $recurring_expense);
$recurring_expense->service()->triggeredActions($request)->save();
$this->uploadLogo($request->file('company_logo'), $recurring_expense->company, $recurring_expense);
@ -372,6 +373,7 @@ class RecurringExpenseController extends BaseController
public function store(StoreRecurringExpenseRequest $request)
{
$recurring_expense = $this->recurring_expense_repo->save($request->all(), RecurringExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id));
$recurring_expense->service()->triggeredActions($request)->save();
event(new RecurringExpenseWasCreated($recurring_expense, $recurring_expense->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));

View File

@ -388,7 +388,10 @@ class RecurringInvoiceController extends BaseController
$recurring_invoice = $this->recurring_invoice_repo->save($request->all(), $recurring_invoice);
$recurring_invoice->service()->deletePdf()->save();
$recurring_invoice->service()
->triggeredActions($request)
->deletePdf()
->save();
event(new RecurringInvoiceWasUpdated($recurring_invoice, $recurring_invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));

View File

@ -280,6 +280,7 @@ class TaskController extends BaseController
$old_task = json_decode(json_encode($task));
$task = $this->task_repo->save($request->all(), $task);
$task = $this->task_repo->triggeredActions($request, $task);
if($task->status_order != $old_task->status_order)
$this->task_repo->sortStatuses($old_task, $task);
@ -377,6 +378,7 @@ class TaskController extends BaseController
public function store(StoreTaskRequest $request)
{
$task = $this->task_repo->save($request->all(), TaskFactory::create(auth()->user()->company()->id, auth()->user()->id));
$task = $this->task_repo->triggeredActions($request, $task);
event(new TaskWasCreated($task, $task->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));

View File

@ -238,6 +238,7 @@ class BillingPortalPurchase extends Component
{
$company = $this->subscription->company;
$user = $this->subscription->user;
$user->setCompany($company);
$client_repo = new ClientRepository(new ClientContactRepository());

View File

@ -75,12 +75,6 @@ class PaymentAmountsBalanceRule implements Rule
return true;
}
// nlog(request()->input('invoices'));
// nlog($payment_amounts);
// nlog($invoice_amounts);
// nlog(request()->all());
nlog($payment_amounts ." >= " . $invoice_amounts);
return round($payment_amounts,2) >= round($invoice_amounts,2);
}

View File

@ -74,7 +74,6 @@ class BaseTransformer
->where('id_number', $client_name);
if ($client_id_search->count() >= 1) {
// nlog("found via id number => {$client_id_search->first()->id}");
return $client_id_search->first()->id;
}
@ -83,7 +82,6 @@ class BaseTransformer
->where('name', $client_name);
if ($client_name_search->count() >= 1) {
// nlog("found via name {$client_name_search->first()->id}");
return $client_name_search->first()->id;
}
}
@ -94,13 +92,10 @@ class BaseTransformer
)->where('email', $client_email);
if ($contacts->count() >= 1) {
// nlog("found via contact {$contacts->first()->client_id}");
return $contacts->first()->client_id;
}
}
// nlog("did not find client");
return null;
}

View File

@ -66,14 +66,12 @@ class BaseTransformer
if ( $client_id_search->count() >= 1 ) {
return $client_id_search->first()->id;
nlog("found via id number");
}
$client_name_search = $clients->where( 'name', $client_name );
if ( $client_name_search->count() >= 1 ) {
return $client_name_search->first()->id;
nlog("found via name");
}
if ( ! empty( $client_email ) ) {
@ -82,10 +80,8 @@ class BaseTransformer
if ( $contacts->count() >= 1 ) {
return $contacts->first()->client_id;
nlog("found via contact");
}
}
// nlog("did not find client");
return null;
}

View File

@ -483,8 +483,6 @@ class CompanyImport implements ShouldQueue
$tmp_company->db = config('database.default');
$tmp_company->account_id = $this->account->id;
nlog($tmp_company);
if(Ninja::isHosted())
$tmp_company->subdomain = MultiDB::randomSubdomainGenerator();
else

View File

@ -46,7 +46,7 @@ class SupportMessageSent extends Mailable
$log_file->seek(PHP_INT_MAX);
$last_line = $log_file->key();
$lines = new LimitIterator($log_file, $last_line - 100, $last_line);
$lines = new LimitIterator($log_file, max(0,$last_line - 100), $last_line);
$log_lines = iterator_to_array($lines);
}
@ -76,7 +76,7 @@ class SupportMessageSent extends Mailable
->replyTo($user->email, $user->present()->name())
->subject($subject)
->view('email.support.message', [
'support_message' => $this->data['message'],
'support_message' => nl2br($this->data['message']),
'system_info' => $system_info,
'laravel_log' => $log_lines,
'logo' => $company->present()->logo(),

View File

@ -99,6 +99,7 @@ class Company extends BaseModel
'report_include_drafts',
'client_registration_fields',
'convert_rate_to_client',
'markdown_email_enabled',
];
protected $hidden = [

View File

@ -255,9 +255,6 @@ class CreditCard
$response = $this->eway_driver->init()->eway->createTransaction(\Eway\Rapid\Enum\ApiMethod::DIRECT, $transaction);
nlog('eway');
nlog($response);
$response_status = ErrorCode::getStatus($response->ResponseMessage);
if(!$response_status['success']){

View File

@ -151,8 +151,6 @@ class PayFastPaymentDriver extends BaseDriver
if($this->company_gateway->getConfigField('passphrase'))
$fields['passphrase'] = $this->company_gateway->getConfigField('passphrase');
nlog(http_build_query($fields));
return md5(http_build_query($fields));
}

View File

@ -13,6 +13,7 @@ namespace App\Repositories;
use App\Factory\ClientFactory;
use App\Models\Client;
use App\Models\Company;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\SavesDocuments;
@ -60,9 +61,9 @@ class ClientRepository extends BaseRepository
$client->fill($data);
if(auth()->user() && !$client->country_id){
$client->country_id = auth()->user()->company()->settings->country_id;
if(!$client->country_id){
$company = Company::find($client->company_id);
$client->country_id = $company->settings->country_id;
}

View File

@ -203,7 +203,7 @@ class TaskRepository extends BaseRepository
$last = end($log);
if($last[1] !== 0){
if(is_array($last) && $last[1] !== 0){
$new = [time(), 0];
$log = array_merge($log, [$new]);
@ -212,6 +212,7 @@ class TaskRepository extends BaseRepository
}
return $task;
}
public function stop(Task $task)
@ -220,7 +221,7 @@ class TaskRepository extends BaseRepository
$last = end($log);
if($last[1] === 0){
if(is_array($last) && $last[1] === 0){
$last[1] = time();
@ -231,5 +232,21 @@ class TaskRepository extends BaseRepository
$task->save();
}
return $task;
}
public function triggeredActions($request, $task)
{
if ($request->has('start') && $request->input('start') == 'true') {
$task = $this->start($task);
}
if ($request->has('stop') && $request->input('stop') == 'true') {
$task = $this->stop($task);
}
return $task;
}
}

View File

@ -41,70 +41,15 @@ class HandleRestore extends AbstractService
foreach ($this->invoice->payments as $payment) {
//restore the payment record
// $payment->restore();
$this->invoice->restore();
// //determine the paymentable amount before paymentable restoration
// $pre_restore_amount = $payment->paymentables()
// ->where('paymentable_type', '=', 'invoices')
// ->sum(\DB::raw('amount'));
// nlog("first pre restore amount = {$pre_restore_amount}");
// $pre_restore_amount -= $payment->paymentables()
// ->where('paymentable_type', '=', 'invoices')
// ->sum(\DB::raw('refunded'));
// nlog("second pre restore amount = {$pre_restore_amount}");
//restore the paymentables
// $payment->paymentables()
// ->where('paymentable_type', '=', 'invoices')
// ->where('paymentable_id', $this->invoice->id)
// ->restore();
//determine the post restore paymentable amount (we need to increment the payment amount by the difference between pre and post)
// $payment_amount = $payment->paymentables()
// ->where('paymentable_type', '=', 'invoices')
// ->sum(\DB::raw('amount'));
// nlog("first payment_amount = {$payment_amount}");
// $payment_amount -= $payment->paymentables()
// ->where('paymentable_type', '=', 'invoices')
// ->sum(\DB::raw('refunded'));
// nlog("second payment_amount = {$payment_amount}");
// nlog($payment->amount . " == " . $payment_amount);
// if ($payment->amount == $payment_amount) {
// $payment->is_deleted = false;
// $payment->save();
// $this->payment_total += $payment_amount;
// } else {
// $payment->is_deleted = false;
// $payment->amount += ($payment_amount - $pre_restore_amount);
// $payment->applied += ($payment_amount - $pre_restore_amount);
// $payment->save();
// $this->payment_total += ($payment_amount - $pre_restore_amount);
// }
}
//adjust ledger balance
$this->invoice->ledger()->updateInvoiceBalance($this->invoice->balance, "Restored invoice {$this->invoice->number}")->save();
//adjust paid to dates
// $this->invoice->client->service()->updatePaidToDate($this->payment_total)->save();
$this->invoice->client->service()->updateBalance($this->invoice->balance)->save();
// you only need to touch the ledger ONCE per transaction.
// $this->invoice->ledger()->updatePaymentBalance($this->payment_total*-1, "Restored payment for invoice {$this->invoice->number}")->save();
$this->windBackInvoiceNumber();
$this->invoice->is_deleted = false;

View File

@ -96,10 +96,10 @@ class MarkPaid extends AbstractService
$payment->ledger()
->updatePaymentBalance($payment->amount * -1);
$client = $this->invoice->client->fresh();
$client->paid_to_date += $payment->amount;
$client->balance += $payment->amount * -1;
$client->save();
$this->invoice->client->fresh();
$this->invoice->client->paid_to_date += $payment->amount;
$this->invoice->client->balance += $payment->amount * -1;
$this->invoice->client->push();
$this->invoice = $this->invoice
->service()

View File

@ -47,12 +47,6 @@ class MarkSent extends AbstractService
->updateBalance($adjustment, true)
->save();
/*Adjust client balance*/
$this->client
->service()
->updateBalance($adjustment)
->save();
/*Update ledger*/
$this->invoice
->ledger()
@ -68,6 +62,12 @@ class MarkSent extends AbstractService
->setReminder()
->save();
/*Adjust client balance*/
$this->client->fresh();
$this->client->balance += $adjustment;
$this->client->save();
$this->invoice->markInvitationsSent();
event(new InvoiceWasUpdated($this->invoice, $this->invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));

View File

@ -57,6 +57,9 @@ class TriggeredActions extends AbstractService
$this->invoice = $this->invoice->service()->markSent()->save();
}
if ($this->request->has('cancel') && $this->request->input('cancel') == 'true') {
$this->invoice = $this->invoice->service()->handleCancellation()->save();
}
return $this->invoice;
}

View File

@ -678,7 +678,7 @@ class Design extends BaseDesign
$elements = [
['element' => 'div', 'properties' => ['style' => 'display: flex; flex-direction: column;'], 'elements' => [
['element' => 'p', 'content' => strtr(str_replace("labels", "", $_variables['values']['$entity.public_notes']), $_variables), 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;']],
['element' => 'p', 'content' => strtr(str_replace(["labels","values"], ["",""], $_variables['values']['$entity.public_notes']), $_variables), 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;']],
['element' => 'p', 'content' => '', 'properties' => ['style' => 'text-align: left; display: flex; flex-direction: column; page-break-inside: auto;'], 'elements' => [
['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['hidden' => $this->entityVariableCheck('$entity.terms'), 'data-ref' => 'total_table-terms-label', 'style' => 'font-weight: bold; text-align: left; margin-top: 1rem;']],
['element' => 'span', 'content' => strtr(str_replace("labels", "", $_variables['values']['$entity.terms']), $_variables['labels']), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']],

View File

@ -50,6 +50,10 @@ class TriggeredActions extends AbstractService
$this->quote = $this->quote->service()->convert()->save();
}
if ($this->request->has('approve') && $this->request->input('approve') == 'true' && in_array($this->quote->status_id, [Quote::STATUS_SENT, Quote::STATUS_DRAFT])) {
$this->quote = $this->quote->service()->convert()->save();
}
return $this->quote;
}

View File

@ -167,6 +167,7 @@ class CompanyTransformer extends EntityTransformer
'report_include_drafts' => (bool) $company->report_include_drafts,
'client_registration_fields' => (array) $company->client_registration_fields,
'convert_rate_to_client' => (bool) $company->convert_rate_to_client,
'markdown_email_enabled' => (bool) $company->markdown_email_enabled,
];
}

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.3.77',
'app_tag' => '5.3.77',
'app_version' => '5.3.78',
'app_tag' => '5.3.78',
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''),

View File

@ -1,5 +1,6 @@
<?php
use App\Models\Company;
use App\Models\Gateway;
use App\Utils\Ninja;
use Illuminate\Database\Migrations\Migration;
@ -27,6 +28,10 @@ class ReverseAppleDomainForHosted extends Migration
}
}
Company::cursor()->each(function ($company){
$company->update(['markdown_email_enabled' => true]);
});
}
/**

View File

@ -1,6 +1,8 @@
@component('email.template.admin', ['settings' => $settings, 'logo' => $logo ?? 'https://www.invoiceninja.com/wp-content/uploads/2015/10/logo-white-horizontal-1.png'])
{{-- Body --}}
{{ $support_message }}
{!! $support_message !!}
<hr>
{!! str_replace('\n', '<br>', $system_info) !!}

View File

@ -211,5 +211,76 @@ class RecurringExpenseApiTest extends TestCase
$this->assertEquals(RecurringInvoice::STATUS_PAUSED, $arr['data'][0]['status_id']);
}
public function testRecurringExpenseStartedWithTriggeredAction()
{
$data = [
'ids' => [$this->encodePrimaryKey($this->recurring_expense->id)],
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->put('/api/v1/recurring_expenses/'.$this->recurring_expense->hashed_id.'?start=true', []);
$arr = $response->json();
$this->assertEquals(RecurringInvoice::STATUS_ACTIVE, $arr['data']['status_id']);
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->put('/api/v1/recurring_expenses/'.$this->recurring_expense->hashed_id.'?stop=true', []);
$arr = $response->json();
$this->assertEquals(RecurringInvoice::STATUS_PAUSED, $arr['data']['status_id']);
}
public function testRecurringExpensePostWithStartAction()
{
$data = [
'amount' => 10,
'client_id' => $this->client->hashed_id,
'number' => '123321',
'frequency_id' => 5,
'remaining_cycles' =>5
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/recurring_expenses?start=true', $data);
$response->assertStatus(200);
$arr = $response->json();
$this->assertEquals(RecurringInvoice::STATUS_ACTIVE, $arr['data']['status_id']);
}
public function testRecurringExpensePostWithStopAction()
{
$data = [
'amount' => 10,
'client_id' => $this->client->hashed_id,
'number' => '1233x21',
'frequency_id' => 5,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/recurring_expenses?stop=true', $data);
$response->assertStatus(200);
$arr = $response->json();
$this->assertEquals(RecurringInvoice::STATUS_PAUSED, $arr['data']['status_id']);
}
}

View File

@ -50,6 +50,79 @@ class RecurringInvoiceTest extends TestCase
$this->makeTestData();
}
public function testPostRecurringInvoice()
{
$data = [
'frequency_id' => 1,
'status_id' => 1,
'discount' => 0,
'is_amount_discount' => 1,
'po_number' => '3434343',
'public_notes' => 'notes',
'is_deleted' => 0,
'custom_value1' => 0,
'custom_value2' => 0,
'custom_value3' => 0,
'custom_value4' => 0,
'status' => 1,
'client_id' => $this->encodePrimaryKey($this->client->id),
'line_items' => $this->buildLineItems(),
'remaining_cycles' => -1,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/recurring_invoices/', $data)
->assertStatus(200);
$arr = $response->json();
$this->assertEquals(RecurringInvoice::STATUS_DRAFT, $arr['data']['status_id']);
}
public function testPostRecurringInvoiceWithStartAndStop()
{
$data = [
'frequency_id' => 1,
'status_id' => 1,
'discount' => 0,
'is_amount_discount' => 1,
'po_number' => '3434343',
'public_notes' => 'notes',
'is_deleted' => 0,
'custom_value1' => 0,
'custom_value2' => 0,
'custom_value3' => 0,
'custom_value4' => 0,
'status' => 1,
'client_id' => $this->encodePrimaryKey($this->client->id),
'line_items' => $this->buildLineItems(),
'remaining_cycles' => -1,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/recurring_invoices?start=true', $data)
->assertStatus(200);
$arr = $response->json();
$this->assertEquals(RecurringInvoice::STATUS_ACTIVE, $arr['data']['status_id']);
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->put('/api/v1/recurring_invoices/'.$arr['data']['id'].'?stop=true', $data)
->assertStatus(200);
$arr = $response->json();
$this->assertEquals(RecurringInvoice::STATUS_PAUSED, $arr['data']['status_id']);
}
public function testRecurringInvoiceList()
{
Client::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id])->each(function ($c) {

View File

@ -90,7 +90,7 @@ class TaskApiTest extends TestCase
$response->assertStatus(200);
$this->assertEquals('taskynumber', $arr['data']['number']);
$this->assertLessThan(5, strlen($arr['data']['time_log']));
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
@ -113,6 +113,23 @@ class TaskApiTest extends TestCase
$this->assertNotEmpty($arr['data']['number']);
}
public function testTaskPostNoDefinedTaskNumber()
{
$data = [
'description' => $this->faker->firstName,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/tasks', $data);
$arr = $response->json();
$response->assertStatus(200);
$this->assertNotEmpty($arr['data']['number']);
}
public function testTaskPostWithActionStart()
{
$data = [
@ -224,4 +241,46 @@ class TaskApiTest extends TestCase
$this->assertTrue($arr['data'][0]['is_deleted']);
}
public function testTaskPostWithStartAction()
{
$data = [
'description' => $this->faker->firstName,
'number' => 'taskynumber2'
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/tasks?start=true', $data);
$arr = $response->json();
$response->assertStatus(200);
$this->assertEquals('taskynumber2', $arr['data']['number']);
$this->assertGreaterThan(5, strlen($arr['data']['time_log']));
}
public function testTaskPostWithStopAction()
{
$data = [
'description' => $this->faker->firstName,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/tasks?stop=true', $data);
$arr = $response->json();
$response->assertStatus(200);
$this->assertLessThan(5, strlen($arr['data']['time_log']));
}
}

View File

@ -182,7 +182,8 @@ class CompanyLedgerTest extends TestCase
//client->balance should = 10
$invoice->service()->markSent()->save();
$this->assertEquals($invoice->client->balance, 10);
$this->client = Client::find($this->client->id);
$this->assertEquals($this->client->balance, 10);
$invoice_ledger = $invoice->company_ledger->sortByDesc('id')->first();