Updated translations for payment schedules and invoice outstanding tasks
This commit is contained in:
parent
e50ef1d373
commit
0d9651f95c
|
|
@ -95,10 +95,11 @@ class PaymentScheduleRequest extends Request
|
|||
$input['parameters']['schedule'] = $this->generateSchedule($input['frequency_id'], $input['remaining_cycles'], Carbon::parse($due_date));
|
||||
}
|
||||
|
||||
// $input['next_run'] = $input['parameters']['schedule'][0]['date'];
|
||||
|
||||
$input['remaining_cycles'] = count($input['parameters']['schedule']);
|
||||
|
||||
$input['next_run_client'] = $input['next_run'];
|
||||
$input['next_run'] = Carbon::parse($input['next_run'])->addSeconds($this->invoice->company->timezone_offset())->format('Y-m-d');
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +127,7 @@ class PaymentScheduleRequest extends Request
|
|||
];
|
||||
}
|
||||
|
||||
if($adjustment > 0) {
|
||||
if($adjustment != 0) {
|
||||
$schedule[$remaining_cycles-1]['amount'] += $adjustment;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -834,7 +834,7 @@ class Invoice extends BaseModel
|
|||
return $reminder_schedule;
|
||||
}
|
||||
|
||||
public function paymentSchedule(): array
|
||||
public function paymentSchedule(bool $formatted = false): mixed
|
||||
{
|
||||
|
||||
$schedule = \App\Models\Scheduler::where('company_id', $this->company_id)
|
||||
|
|
@ -843,15 +843,63 @@ class Invoice extends BaseModel
|
|||
->first();
|
||||
|
||||
if (! $schedule) {
|
||||
|
||||
if($formatted){
|
||||
return '';
|
||||
}
|
||||
else{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
if(!$formatted){
|
||||
return collect($schedule->parameters['schedule'])->map(function ($item) use ($schedule) {
|
||||
return [
|
||||
'date' => $item['date'],
|
||||
'date' => $this->formatDate($item['date'], $this->client->date_format()),
|
||||
'amount' => $item['is_amount'] ? \App\Utils\Number::formatMoney($item['amount'], $this->client) : $item['amount'] ." %",
|
||||
'auto_bill' => $schedule->parameters['auto_bill'],
|
||||
];
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
|
||||
$formatted_string = "<div id=\"payment-schedule\">";
|
||||
|
||||
foreach($schedule->parameters['schedule'] as $item){
|
||||
$amount = $item['is_amount'] ? $item['amount'] : round($this->amount * ($item['amount']/100),2);
|
||||
$amount = \App\Utils\Number::formatMoney($amount, $this->client);
|
||||
|
||||
$formatted_string .= "<p><span class=\"payment-schedule-date\">".$this->formatDate($item['date'], $this->client->date_format()) . "</span> - <span class=\"payment-schedule-amount\"> " . $amount."</span></p>";
|
||||
}
|
||||
|
||||
$formatted_string .= "</div>";
|
||||
|
||||
return htmlspecialchars($formatted_string, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
}
|
||||
|
||||
public function paymentScheduleInterval(): string
|
||||
{
|
||||
$schedule = \App\Models\Scheduler::where('company_id', $this->company_id)
|
||||
->where('template', 'payment_schedule')
|
||||
->where('parameters->invoice_id', $this->hashed_id)
|
||||
->first();
|
||||
|
||||
if(!$schedule)
|
||||
return '';
|
||||
|
||||
$schedule_array = $schedule->parameters['schedule'] ?? [];
|
||||
|
||||
$index = 0;
|
||||
|
||||
foreach($schedule_array as $key => $item){
|
||||
if($date = Carbon::parse($item['date'])->eq(Carbon::parse($schedule->next_run_client))){
|
||||
$index = $key;
|
||||
}
|
||||
}
|
||||
|
||||
$amount = $schedule_array[$index]['is_amount'] ? \App\Utils\Number::formatMoney($schedule_array[$index]['amount'], $this->client) : \App\Utils\Number::formatMoney(($schedule_array[$index]['amount']/100)*$this->amount, $this->client);
|
||||
|
||||
return ctrans('texts.payment_schedule_interval', ['index' => $index+1, 'total' => count($schedule_array), 'amount' => $amount]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,15 +54,8 @@ class PaymentSchedule
|
|||
return;
|
||||
}
|
||||
|
||||
nlog($next_schedule);
|
||||
|
||||
if($next_schedule['is_amount']){
|
||||
nlog("is an amount");
|
||||
$amount = $next_schedule['amount'];
|
||||
}
|
||||
else{
|
||||
$amount = round(($next_schedule['amount']/100)*$invoice->amount, 2);
|
||||
}
|
||||
$amount = $next_schedule['is_amount'] ? $next_schedule['amount'] : round(($next_schedule['amount']/100)*$invoice->amount, 2);
|
||||
|
||||
$amount = min($amount, $invoice->amount);
|
||||
|
||||
|
|
@ -70,17 +63,12 @@ class PaymentSchedule
|
|||
$amount = $invoice->balance;
|
||||
}
|
||||
|
||||
nlog("amount to add: {$amount}");
|
||||
nlog("invoice partial before: {$invoice->partial}");
|
||||
$invoice->partial += $amount;
|
||||
$invoice->partial_due_date = $next_schedule['date'];
|
||||
$invoice->due_date = Carbon::parse($next_schedule['date'])->addDay()->format('Y-m-d');
|
||||
|
||||
$invoice->save();
|
||||
|
||||
|
||||
nlog("invoice partial after: {$invoice->partial}");
|
||||
|
||||
if($this->scheduler->parameters['auto_bill']){
|
||||
|
||||
try{
|
||||
|
|
|
|||
|
|
@ -190,7 +190,14 @@ class HtmlEngine
|
|||
$data['$tax_info'] = ['value' => $this->taxLabel(), 'label' => ''];
|
||||
$data['$net'] = ['value' => '', 'label' => ctrans('texts.net')];
|
||||
|
||||
$data['$payment_schedule'] = ['value' => '', 'label' => ctrans('texts.payment_schedule')];
|
||||
$data['$payment_schedule_interval'] = ['value' => '', 'label' => ctrans('texts.payment_schedule')];
|
||||
|
||||
if ($this->entity_string == 'invoice' || $this->entity_string == 'recurring_invoice') {
|
||||
|
||||
$data['$payment_schedule'] = ['value' => $this->entity->paymentSchedule(true), 'label' => ctrans('texts.payment_schedule')];
|
||||
$data['$payment_schedule_interval'] = ['value' => $this->entity->paymentScheduleInterval(), 'label' => ctrans('texts.payment_schedule')];
|
||||
|
||||
$data['$entity'] = ['value' => ctrans('texts.invoice'), 'label' => ctrans('texts.invoice')];
|
||||
$data['$number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.invoice_number')];
|
||||
$data['$invoice'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.invoice_number')];
|
||||
|
|
|
|||
|
|
@ -5606,7 +5606,11 @@ $lang = array(
|
|||
'schedule_frequency_help' => 'The interval time between each payment',
|
||||
'first_payment_date' => 'First Payment Date',
|
||||
'first_payment_date_help' => 'The date of the first payment',
|
||||
|
||||
'payment_schedule_interval' => 'Payment :index of :total for :amount',
|
||||
'auto_send' => 'Auto Send',
|
||||
'auto_send_help' => 'Automatically emails the invoice to the client',
|
||||
'include_project_tasks' => 'Include Project Tasks',
|
||||
'include_project_tasks_help' => 'Also invoice tasks that are part of a project',
|
||||
);
|
||||
|
||||
return $lang;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,93 @@ class SchedulerTest extends TestCase
|
|||
|
||||
}
|
||||
|
||||
|
||||
public function testPaymentScheduleCalculationsIsPercentageWithAutoBill()
|
||||
{
|
||||
$settings = $this->company->settings;
|
||||
$settings->use_credits_payment = 'off';
|
||||
$settings->use_unapplied_payment = 'off';
|
||||
$this->company->settings = $settings;
|
||||
$this->company->save();
|
||||
|
||||
\App\Models\Credit::where('client_id', $this->client->id)->delete();
|
||||
|
||||
$invoice = Invoice::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'date' => now()->format('Y-m-d'),
|
||||
'due_date' => now()->addDays(30)->format('Y-m-d'),
|
||||
'partial' => 0,
|
||||
'partial_due_date' => null,
|
||||
'amount' => 300.00,
|
||||
'balance' => 300.00,
|
||||
'status_id' => Invoice::STATUS_SENT,
|
||||
]);
|
||||
|
||||
|
||||
$data = [
|
||||
'name' => 'A test payment schedule scheduler',
|
||||
'frequency_id' => 0,
|
||||
'next_run' => now()->format('Y-m-d'),
|
||||
'template' => 'payment_schedule',
|
||||
'parameters' => [
|
||||
'invoice_id' => $invoice->hashed_id,
|
||||
'auto_bill' => true,
|
||||
'schedule' => [
|
||||
[
|
||||
'id' => 1,
|
||||
'date' => now()->format('Y-m-d'),
|
||||
'amount' => 10,
|
||||
'is_amount' => false,
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'date' => now()->addDays(30)->format('Y-m-d'),
|
||||
'amount' => 90,
|
||||
'is_amount' => false,
|
||||
]
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/task_schedulers', $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$arr = $response->json();
|
||||
|
||||
$scheduler = Scheduler::find($this->decodePrimaryKey($arr['data']['id']));
|
||||
|
||||
$this->assertNotNull($scheduler);
|
||||
|
||||
$scheduler->service()->runTask();
|
||||
|
||||
$invoice = $invoice->fresh();
|
||||
|
||||
$this->assertEquals(30, $invoice->partial);
|
||||
$this->assertEquals(now()->format('Y-m-d'), $invoice->partial_due_date->format('Y-m-d'));
|
||||
|
||||
$scheduler = $scheduler->fresh();
|
||||
|
||||
$this->assertEquals(now()->addDays(30)->format('Y-m-d'), $scheduler->next_run->format('Y-m-d'));
|
||||
|
||||
$this->travelTo(now()->addDays(30));
|
||||
|
||||
$scheduler->service()->runTask();
|
||||
|
||||
$invoice = $invoice->fresh();
|
||||
|
||||
$this->assertEquals(300, $invoice->partial);
|
||||
$this->assertEquals(now()->format('Y-m-d'), $invoice->partial_due_date->format('Y-m-d'));
|
||||
|
||||
$this->travelBack();
|
||||
}
|
||||
|
||||
|
||||
public function testPaymentScheduleCalculationsIsAmountWithAutoBill()
|
||||
{
|
||||
$settings = $this->company->settings;
|
||||
|
|
|
|||
Loading…
Reference in New Issue