1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-11 05:32:39 +01:00

Merge pull request #7011 from turbo124/v5-develop

Minor fixes for Required client info + Payment Failed Mailer
This commit is contained in:
David Bomba 2021-12-05 18:39:12 +11:00 committed by GitHub
commit dbf84f7e50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 744 additions and 582 deletions

View File

@ -46,7 +46,14 @@ class CloneQuoteToInvoiceFactory
$invoice->date = now()->format('Y-m-d');
$invoice->balance = 0;
$invoice->deleted_at = null;
$invoice->next_send_date = null;
$invoice->reminder1_sent = null;
$invoice->reminder2_sent = null;
$invoice->reminder3_sent = null;
$invoice->reminder_last_sent = null;
$invoice->last_sent_date = null;
$invoice->last_viewed = null;
return $invoice;
}
}

View File

@ -36,7 +36,7 @@ class ExpenseFilters extends QueryFilters
}
return $this->builder->where(function ($query) use ($filter) {
$query->where('expenses.name', 'like', '%'.$filter.'%')
$query->where('expenses.public_notes', 'like', '%'.$filter.'%')
->orWhere('expenses.id_number', 'like', '%'.$filter.'%')
->orWhere('expenses.custom_value1', 'like', '%'.$filter.'%')
->orWhere('expenses.custom_value2', 'like', '%'.$filter.'%')
@ -94,7 +94,10 @@ class ExpenseFilters extends QueryFilters
{
$sort_col = explode('|', $sort);
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
if(is_array($sort_col) && in_array($sort_col[1], ['asc', 'desc']) && in_array($sort_col[0], ['public_notes', 'date', 'id_number', 'custom_value1', 'custom_value2', 'custom_value3', 'custom_value4']))
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
return $this->builder;
}
/**

View File

@ -60,8 +60,15 @@ class ContactForgotPasswordController extends Controller
{
$account_id = $request->has('account_id') ? $request->get('account_id') : 1;
$account = Account::find($account_id);
$company = $account->companies->first();
if($request->has('company_key'))
$company = Company::where('company_key', $request->input('company_key'))->first();
else
$company = $account->companies->first();
if(!$account)
$account = Account::first();
return $this->render('auth.passwords.request', [
'title' => 'Client Password Reset',
'passwordEmailRoute' => 'client.password.email',
@ -90,7 +97,9 @@ class ContactForgotPasswordController extends Controller
// $user = MultiDB::hasContact($request->input('email'));
$company = Company::where('company_key', $request->input('company_key'))->first();
$contact = MultiDB::findContact(['company_id' => $company->id, 'email' => $request->input('email')]);
//$contact = MultiDB::findContact(['company_id' => $company->id, 'email' => $request->input('email')]);
nlog(['company_id' => $company->id, 'email' => $request->input('email')]);
$contact = ClientContact::where(['company_id' => $company->id, 'email' => $request->input('email')])->first();
$response = false;

View File

@ -255,7 +255,7 @@ class BaseController extends Controller
$query->where('expenses.user_id', $user->id)->orWhere('expenses.assigned_user_id', $user->id);
},
'company.groups' => function ($query) use ($updated_at, $user) {
$query->where('updated_at', '>=', $updated_at)->with('documents');
$query->whereNotNull('updated_at')->with('documents');
// if(!$user->isAdmin())
// $query->where('group_settings.user_id', $user->id);
@ -275,7 +275,7 @@ class BaseController extends Controller
},
'company.payment_terms'=> function ($query) use ($updated_at, $user) {
$query->where('updated_at', '>=', $updated_at);
$query->whereNotNull('updated_at');
if(!$user->isAdmin())
$query->where('payment_terms.user_id', $user->id);
@ -346,7 +346,6 @@ class BaseController extends Controller
},
'company.subscriptions'=> function ($query) use($updated_at, $user) {
// $query->where('updated_at', '>=', $updated_at);
$query->whereNotNull('updated_at');
if(!$user->isAdmin())

View File

@ -15,6 +15,7 @@ namespace App\Http\Controllers\ClientPortal;
use App\Http\Controllers\Controller;
use App\Http\Requests\ClientPortal\Documents\ShowDocumentRequest;
use App\Http\Requests\Document\DownloadMultipleDocumentsRequest;
use App\Libraries\MultiDB;
use App\Models\Document;
use App\Utils\TempFile;
use App\Utils\Traits\MakesHash;
@ -55,6 +56,8 @@ class DocumentController extends Controller
public function publicDownload(string $document_hash)
{
MultiDB::documentFindAndSetDb($document_hash);
$document = Document::where('hash', $document_hash)->firstOrFail();
$headers = [];

View File

@ -71,6 +71,8 @@ class InvitationController extends Controller
if(!in_array($entity, ['invoice', 'credit', 'quote', 'recurring_invoice']))
return response()->json(['message' => 'Invalid resource request']);
$is_silent = 'false';
$key = $entity.'_id';
$entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation';
@ -111,8 +113,16 @@ class InvitationController extends Controller
$this->fireEntityViewedEvent($invitation, $entity);
}
else{
$is_silent = 'true';
return redirect()->route('client.'.$entity.'.show', [$entity => $this->encodePrimaryKey($invitation->{$key}), 'silent' => $is_silent]);
}
return redirect()->route('client.'.$entity.'.show', [$entity => $this->encodePrimaryKey($invitation->{$key})]);
}
private function fireEntityViewedEvent($invitation, $entity_string)

View File

@ -71,7 +71,8 @@ class NinjaPlanController extends Controller
{
//harvest the current plan
$data = [];
$data['late_invoice'] = false;
if(MultiDB::findAndSetDbByAccountKey(Auth::guard('contact')->user()->client->custom_value2))
{
$account = Account::where('key', Auth::guard('contact')->user()->client->custom_value2)->first();

View File

@ -74,7 +74,7 @@ class DocumentsTable extends Component
break;
case 'expenses':
$this->query = $this->expenses();
// $this->query = $this->expenses();
break;
case 'invoices':

View File

@ -60,7 +60,7 @@ class RequiredClientInfo extends Component
'contact_first_name' => 'first_name',
'contact_last_name' => 'last_name',
// 'contact_email' => 'email',
'contact_email' => 'email',
// 'contact_phone' => 'phone',
];

View File

@ -49,7 +49,7 @@ class SetDomainNameDb
];
if($company = MultiDB::findAndSetDbByDomain($query)){
$request->request->add(['account_id' => $company->account_id]);
$request->request->add(['account_id' => $company->account_id, 'company_key' => $company->company_key]);
}
else
{
@ -71,7 +71,7 @@ class SetDomainNameDb
];
if($company = MultiDB::findAndSetDbByDomain($query)){
$request->request->add(['account_id' => $company->account_id]);
$request->request->add(['account_id' => $company->account_id, 'company_key' => $company->company_key]);
}
else
{

View File

@ -17,6 +17,7 @@ class ShowPlanSwitchRequest extends FormRequest
*/
public function authorize()
{
return (bool)$this->recurring_invoice->subscription->allow_plan_changes;
}

View File

@ -81,6 +81,9 @@ class StoreCompanyRequest extends Request
}
}
if(array_key_exists('portal_domain', $input))
$input['portal_domain'] = strtolower($input['portal_domain']);
$this->replace($input);
}
}

View File

@ -68,8 +68,10 @@ class UpdateCompanyRequest extends Request
{
$input = $this->all();
if(Ninja::isHosted() && array_key_exists('portal_domain', $input) && strlen($input['portal_domain']) > 1)
if(Ninja::isHosted() && array_key_exists('portal_domain', $input) && strlen($input['portal_domain']) > 1){
$input['portal_domain'] = $this->addScheme($input['portal_domain']);
$input['portal_domain'] = strtolower($input['portal_domain']);
}
if (array_key_exists('settings', $input)) {
$input['settings'] = $this->filterSaveableSettings($input['settings']);

View File

@ -62,20 +62,30 @@ class BaseTransformer
public function getClient($client_name, $client_email) {
$clients = $this->maps['company']->clients;
$clients = $clients->where( 'id_number', $client_name );
$client_id_search = $clients->where( 'id_number', $client_name );
if ( $clients->count() >= 1 ) {
return $clients->first()->id;
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 ) ) {
$contacts = ClientContact::where( 'company_id', $this->maps['company']->id )
->where( 'email', $client_email );
if ( $contacts->count() >= 1 ) {
return $contacts->first()->client_id;
nlog("found via contact");
}
}
nlog("did not find client");
return null;
}

View File

@ -92,7 +92,7 @@ class InvoiceTransformer extends BaseTransformer {
'amount' => $this->getFloat( $invoice_data, 'invoice.amount' ),
],
];
} elseif ( isset( $transformed['amount'] ) && isset( $transformed['balance'] ) ) {
} elseif ( isset( $transformed['amount'] ) && isset( $transformed['balance'] ) && ($transformed['amount'] != $transformed['balance'])) {
$transformed['payments'] = [
[
'date' => isset( $invoice_data['payment.date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['payment.date'] ) ) : date( 'y-m-d' ),
@ -126,6 +126,8 @@ class InvoiceTransformer extends BaseTransformer {
}
$transformed['line_items'] = $line_items;
nlog($transformed);
return $transformed;
}
}

View File

@ -53,7 +53,7 @@ class AutoBill
nlog("autobill {$this->invoice->id}");
$this->invoice->service()->autoBill()->save();
$this->invoice->service()->autoBill();
}
catch(\Exception $e) {

View File

@ -115,9 +115,6 @@ class CreateEntityPdf implements ShouldQueue
/* Set customized translations _NOW_ */
$t->replace(Ninja::transformTranslations($this->client->getMergedSettings()));
$translate = microtime(true);
// nlog("Translate ". $translate - $start);
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
return (new Phantom)->generate($this->invitation);
}
@ -142,9 +139,6 @@ class CreateEntityPdf implements ShouldQueue
$entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->client->getSetting($entity_design_id));
// if(!$this->company->account->hasFeature(Account::FEATURE_DIFFERENT_DESIGNS))
// $entity_design_id = 2;
$design = Design::find($entity_design_id);
/* Catch all in case migration doesn't pass back a valid design */
@ -153,9 +147,6 @@ class CreateEntityPdf implements ShouldQueue
$html = new HtmlEngine($this->invitation);
$design_time = microtime(true);
// nlog("Design ". $design_time - $translate);
if ($design->is_custom) {
$options = [
'custom_partials' => json_decode(json_encode($design->design), true)
@ -167,9 +158,6 @@ class CreateEntityPdf implements ShouldQueue
$variables = $html->generateLabelsAndValues();
$labels_time = microtime(true);
// nlog("Labels ". $labels_time - $design_time);
$state = [
'template' => $template->elements([
'client' => $this->client,
@ -192,10 +180,6 @@ class CreateEntityPdf implements ShouldQueue
->design($template)
->build();
$template_time = microtime(true);
// nlog("Template Build ". $template_time - $labels_time);
$pdf = null;
try {
@ -215,10 +199,6 @@ class CreateEntityPdf implements ShouldQueue
info($maker->getCompiledHTML());
}
$pdf_time = microtime(true);
// nlog("PDF time " . $pdf_time - $template_time);
if ($pdf) {
try{

View File

@ -188,9 +188,9 @@ class CreateRawPdf implements ShouldQueue
nlog(print_r($e->getMessage(), 1));
}
// if (config('ninja.log_pdf_html')) {
if (config('ninja.log_pdf_html')) {
info($maker->getCompiledHTML());
// }
}
if ($pdf)
return $pdf;

View File

@ -112,6 +112,9 @@ class EmailEntity implements ShouldQueue
App::setLocale($this->invitation->contact->preferredLocale());
$t->replace(Ninja::transformTranslations($this->settings));
/* Mark entity sent */
$this->entity->service()->markSent()->save();
$nmo = new NinjaMailerObject;
$nmo->mailable = new TemplateEmail($this->email_entity_builder, $this->invitation->contact, $this->invitation);
$nmo->company = $this->company;
@ -124,8 +127,7 @@ class EmailEntity implements ShouldQueue
NinjaMailerJob::dispatchNow($nmo);
/* Mark entity sent */
$this->entity->service()->markSent()->save();
}
private function resolveEntityString() :string

View File

@ -332,18 +332,21 @@ class CSVImport implements ShouldQueue {
$invoice = $invoice->service()->markViewed()->save();
}
if ( $invoice->status_id === Invoice::STATUS_SENT ) {
if( $invoice->status_id === Invoice::STATUS_DRAFT ){
}
elseif ( $invoice->status_id === Invoice::STATUS_SENT ) {
$invoice = $invoice->service()->markSent()->save();
}
if ( $invoice->status_id <= Invoice::STATUS_SENT && $invoice->amount > 0 ) {
if ( $invoice->balance < $invoice->amount ) {
$invoice->status_id = Invoice::STATUS_PARTIAL;
$invoice->save();
} elseif ( $invoice->balance <= 0 ) {
elseif ( $invoice->status_id <= Invoice::STATUS_SENT && $invoice->amount > 0 ) {
if ( $invoice->balance <= 0 ) {
$invoice->status_id = Invoice::STATUS_PAID;
$invoice->save();
}
elseif ( $invoice->balance != $invoice->amount ) {
$invoice->status_id = Invoice::STATUS_PARTIAL;
$invoice->save();
}
}

View File

@ -23,6 +23,7 @@ use App\Models\Company;
use App\Models\Invoice;
use App\Models\PaymentHash;
use App\Models\User;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
@ -35,7 +36,7 @@ use Illuminate\Support\Facades\Mail;
class PaymentFailedMailer implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, UserNotifies;
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, UserNotifies, MakesHash;
public ?PaymentHash $payment_hash;
@ -80,7 +81,7 @@ class PaymentFailedMailer implements ShouldQueue
if($this->payment_hash){
$amount = array_sum(array_column($this->payment_hash->invoices(), 'amount')) + $this->payment_hash->fee_total;
$invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first();
$invoice = Invoice::whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->first();
}
//iterate through company_users

View File

@ -145,7 +145,7 @@ class SendRecurring implements ShouldQueue
if ($invoice->client->getSetting('auto_bill_date') == 'on_send_date' && $invoice->auto_bill_enabled) {
nlog("attempting to autobill {$invoice->number}");
$invoice->service()->autoBill()->save();
$invoice->service()->autoBill();
}
elseif($invoice->client->getSetting('auto_bill_date') == 'on_due_date' && $invoice->auto_bill_enabled) {
@ -153,7 +153,7 @@ class SendRecurring implements ShouldQueue
if($invoice->due_date && Carbon::parse($invoice->due_date)->startOfDay()->lte(now()->startOfDay())) {
nlog("attempting to autobill {$invoice->number}");
$invoice->service()->autoBill()->save();
$invoice->service()->autoBill();
}

View File

@ -69,6 +69,9 @@ class CreditEmailEngine extends BaseEmailEngine
null,
$this->client->locale()
);
$body_template .= '<div class="center">$view_button</div>';
}
if (is_array($this->template_data) && array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0) {

View File

@ -74,6 +74,9 @@ class InvoiceEmailEngine extends BaseEmailEngine
null,
$this->client->locale()
);
$body_template .= '<div class="center">$view_button</div>';
}
if (is_array($this->template_data) && array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0) {

View File

@ -44,6 +44,7 @@ class QuoteEmailEngine extends BaseEmailEngine
public function build()
{
App::forgetInstance('translator');
$t = app('translator');
$t->replace(Ninja::transformTranslations($this->client->getMergedSettings()));
@ -56,21 +57,25 @@ class QuoteEmailEngine extends BaseEmailEngine
} else {
$body_template = $this->client->getSetting('email_template_'.$this->reminder_template);
}
/* Use default translations if a custom message has not been set*/
if (iconv_strlen($body_template) == 0) {
$body_template = trans(
'texts.quote_message',
[
'quote' => $this->quote->number,
'company' => $this->quote->company->present()->name(),
'amount' => Number::formatMoney($this->quote->balance, $this->client),
'amount' => Number::formatMoney($this->quote->amount, $this->client),
],
null,
$this->client->locale()
);
$body_template .= '<div class="center">$view_button</div>';
}
if (is_array($this->template_data) && array_key_exists('subject', $this->template_data) && strlen($this->template_data['subject']) > 0) {
$subject_template = $this->template_data['subject'];
} else {
@ -99,7 +104,6 @@ class QuoteEmailEngine extends BaseEmailEngine
->setViewText(ctrans('texts.view_quote'))
->setInvitation($this->invitation);
if ($this->client->getSetting('pdf_email_attachment') !== false && $this->quote->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
if(Ninja::isHosted())

View File

@ -52,7 +52,8 @@ class TemplateEmail extends Mailable
public function build()
{
$template_name = 'email.template.'.$this->build_email->getTemplate();
$template_name = 'email.template.'.$this->build_email->getTemplate();
if ($this->build_email->getTemplate() == 'light' || $this->build_email->getTemplate() == 'dark') {
$template_name = 'email.template.client';

View File

@ -75,6 +75,7 @@ class Quote extends BaseModel
'assigned_user_id',
'exchange_rate',
'subscription_id',
'uses_inclusive_taxes',
];
protected $casts = [

View File

@ -30,6 +30,7 @@ use App\Models\GatewayType;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\PaymentHash;
use App\Models\PaymentType;
use App\Models\SystemLog;
use App\Services\Subscription\SubscriptionService;
use App\Utils\Ninja;
@ -226,7 +227,7 @@ class BaseDriver extends AbstractPaymentDriver
$_payment = Payment::where('transaction_reference', $data['transaction_reference'])
->where('client_id', $this->client->id)
->exists();
->first();
if($_payment)
return $_payment;
@ -262,12 +263,18 @@ class BaseDriver extends AbstractPaymentDriver
event('eloquent.created: App\Models\Payment', $payment);
if ($this->client->getSetting('client_online_payment_notification'))
if ($this->client->getSetting('client_online_payment_notification') && in_array($status, [Payment::STATUS_COMPLETED, Payment::STATUS_PENDING
]))
$payment->service()->sendEmail();
//todo
//catch any payment failures here also and fire a subsequent failure email if necessary? note only need for delayed payment forms
//perhaps this type of functionality should be handled higher up to provide better context?
event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars()));
if (property_exists($this->payment_hash->data, 'billing_context')) {
if (property_exists($this->payment_hash->data, 'billing_context') && $status == Payment::STATUS_COMPLETED) {
$billing_subscription = \App\Models\Subscription::find($this->payment_hash->data->billing_context->subscription_id);
// To access campaign hash => $this->payment_hash->data->billing_context->campaign;

View File

@ -161,7 +161,8 @@ class PayPal
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_BRAINTREE,
$this->braintree->client
$this->braintree->client,
$this->braintree->client->company
);
throw new PaymentFailed($response->message, 0);

View File

@ -86,7 +86,9 @@ class Bancontact implements MethodInterface
'webhookUrl' => $this->mollie->company_gateway->webhookUrl(),
'metadata' => [
'client_id' => $this->mollie->client->hashed_id,
'hash' => $this->mollie->payment_hash->hash
'hash' => $this->mollie->payment_hash->hash,
'gateway_type_id' => GatewayType::BANCONTACT,
'payment_type_id' => PaymentType::BANCONTACT,
],
]);

View File

@ -89,7 +89,9 @@ class BankTransfer implements MethodInterface
'webhookUrl' => $this->mollie->company_gateway->webhookUrl(),
'metadata' => [
'client_id' => $this->mollie->client->hashed_id,
'hash' => $this->mollie->payment_hash->hash
'hash' => $this->mollie->payment_hash->hash,
'gateway_type_id' => GatewayType::BANK_TRANSFER,
'payment_type_id' => PaymentType::MOLLIE_BANK_TRANSFER,
],
]);

View File

@ -114,7 +114,7 @@ class CreditCard
'name' => $this->mollie->client->name,
'email' => $this->mollie->client->present()->email(),
'metadata' => [
'id' => $this->mollie->client->hashed_id,
'id' => $this->mollie->client->hashed_id
],
]);

View File

@ -86,7 +86,9 @@ class IDEAL implements MethodInterface
'webhookUrl' => $this->mollie->company_gateway->webhookUrl(),
'metadata' => [
'client_id' => $this->mollie->client->hashed_id,
'hash' => $this->mollie->payment_hash->hash
'hash' => $this->mollie->payment_hash->hash,
'gateway_type_id' => GatewayType::IDEAL,
'payment_type_id' => PaymentType::IDEAL,
],
]);

View File

@ -86,7 +86,9 @@ class KBC implements MethodInterface
'webhookUrl' => $this->mollie->company_gateway->webhookUrl(),
'metadata' => [
'client_id' => $this->mollie->client->hashed_id,
'hash' => $this->mollie->payment_hash->hash
'hash' => $this->mollie->payment_hash->hash,
'gateway_type_id' => GatewayType::KBC,
'payment_type_id' => PaymentType::KBC,
],
]);

View File

@ -312,14 +312,31 @@ class MolliePaymentDriver extends BaseDriver
$client = $record->client;
}
else{
nlog("mollie webhook");
nlog($payment);
$client = Client::withTrashed()->find($this->decodePrimaryKey($payment->metadata->client_id));
// sometimes if the user is not returned to the site with a response from Mollie
// we may not have a payment record - in these cases we need to re-construct the payment
// record from the meta data in the payment hash.
if($payment && $payment->metadata->payment_hash){
/* Harvest Payment Hash*/
$payment_hash = PaymentHash::where('hash', $payment->metadata->hash)->first();
$data = [
'gateway_type_id' => $payment->metadata->gateway_type_id,
'amount' => $amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total,
'payment_type' => $payment->metadata->payment_type_id,
'transaction_reference' => $payment->id,
];
$record = $this->createPayment(
$data,
$codes[$payment->status]
);
}
}
$message = [

View File

@ -56,7 +56,6 @@ class Charge
if($cgt->gateway_type_id == GatewayType::BANK_TRANSFER)
return (new ACH($this->stripe))->tokenBilling($cgt, $payment_hash);
nlog(" DB = ".$this->stripe->client->company->db);
$amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total;
$invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first();
@ -119,7 +118,6 @@ class Charge
$data['message'] = $e->getMessage();
break;
}
$this->stripe->processInternallyFailedPayment($this->stripe, $e);

View File

@ -123,7 +123,7 @@ class CreditCard
$data = [
'payment_method' => $this->stripe->payment_hash->data->server_response->payment_method,
'payment_type' => PaymentType::parseCardType(strtolower($stripe_method->card->brand)),
'payment_type' => PaymentType::parseCardType(strtolower($stripe_method->card->brand)) ?: PaymentType::CREDIT_CARD_OTHER,
'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->server_response->amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency()),
'transaction_reference' => optional($this->stripe->payment_hash->data->payment_intent->charges->data[0])->id,
'gateway_type_id' => GatewayType::CREDIT_CARD,

View File

@ -54,6 +54,37 @@ class TaskRepository extends BaseRepository
$task->status_order = $data['status_order'];
}
/*V4 override*/
if (! empty($data['time_details'])) {
$timeLog = [];
foreach ($data['time_details'] as $detail) {
$startTime = strtotime($detail['start_datetime']);
$endTime = false;
if (! empty($detail['end_datetime'])) {
$endTime = strtotime($detail['end_datetime']);
} else {
$duration = 0;
if (! empty($detail['duration_seconds'])) {
$duration += $detail['duration_seconds'];
}
if (! empty($detail['duration_minutes'])) {
$duration += $detail['duration_minutes'] * 60;
}
if (! empty($detail['duration_hours'])) {
$duration += $detail['duration_hours'] * 60 * 60;
}
if ($duration) {
$endTime = $startTime + $duration;
}
}
$timeLog[] = [$startTime, $endTime];
if (! $endTime) {
$data['is_running'] = true;
}
}
$data['time_log'] = json_encode($timeLog);
}
if (isset($data['time_log'])) {
$time_log = json_decode($data['time_log']);
} elseif ($task->time_log) {

View File

@ -36,17 +36,6 @@ class TriggeredActions extends AbstractService
public function run()
{
// if ($this->request->has('auto_bill') && $this->request->input('auto_bill') == 'true') {
// $this->credit = $this->credit->service()->autoBill()->save();
// }
// if ($this->request->has('paid') && $this->request->input('paid') == 'true') {
// $this->credit = $this->credit->service()->markPaid()->save();
// }
// if ($this->request->has('amount_paid') && is_numeric($this->request->input('amount_paid')) ) {
// $this->credit = $this->credit->service()->applyPaymentAmount($this->request->input('amount_paid'))->save();
// }
if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') {
$this->sendEmail();

View File

@ -105,7 +105,7 @@ class AddGatewayFee extends AbstractService
$invoice_item->quantity = 1;
$invoice_item->cost = $gateway_fee;
if ($fees_and_limits = $this->company_gateway->getFeesAndLimits()) {
if ($fees_and_limits = $this->company_gateway->getFeesAndLimits($this->gateway_type_id)) {
$invoice_item->tax_rate1 = $fees_and_limits->fee_tax_rate1;
$invoice_item->tax_rate2 = $fees_and_limits->fee_tax_rate2;
$invoice_item->tax_rate3 = $fees_and_limits->fee_tax_rate3;

View File

@ -130,7 +130,7 @@ class AutoBillInvoice extends AbstractService
info("Auto Bill payment captured for ".$this->invoice->number);
}
return $this->invoice->fresh();
// return $this->invoice->fresh();
}
/**

View File

@ -139,6 +139,7 @@ class InvoiceService
// $this->invoice = (new UpdateBalance($this->invoice, $balance_adjustment, $is_draft))->run();
if ((bool)$this->invoice->is_deleted !== false) {
nlog($this->invoice->number . " is deleted returning");
return $this;
}
@ -245,7 +246,7 @@ class InvoiceService
public function autoBill()
{
$this->invoice = (new AutoBillInvoice($this->invoice, $this->invoice->company->db))->run();
(new AutoBillInvoice($this->invoice, $this->invoice->company->db))->run();
return $this;
}
@ -483,6 +484,10 @@ class InvoiceService
if(!isset($this->invoice->exchange_rate) && $this->invoice->client->currency()->id != (int) $this->invoice->company->settings->currency_id)
$this->invoice->exchange_rate = $this->invoice->client->currency()->exchange_rate;
if($settings->counter_number_applied == 'when_saved'){
$this->invoice->service()->applyNumber()->save();
}
return $this;
}

View File

@ -37,7 +37,7 @@ class TriggeredActions extends AbstractService
public function run()
{
if ($this->request->has('auto_bill') && $this->request->input('auto_bill') == 'true') {
$this->invoice = $this->invoice->service()->autoBill()->save();
$this->invoice = $this->invoice->service()->autoBill();
}
if ($this->request->has('paid') && $this->request->input('paid') == 'true') {

View File

@ -124,10 +124,10 @@ class QuoteService
}
if ($this->quote->client->getSetting('auto_archive_quote')) {
$quote_repo = new QuoteRepository();
$quote_repo->archive($this->quote);
}
// if ($this->quote->client->getSetting('auto_archive_quote')) {
// $quote_repo = new QuoteRepository();
// $quote_repo->archive($this->quote);
// }
return $this;
}

View File

@ -57,7 +57,7 @@ class TriggeredActions extends AbstractService
{
$reminder_template = $this->quote->calculateTemplate('quote');
//$reminder_template = 'payment';
// $reminder_template = 'email_template_quote';
$this->quote->invitations->load('contact.client.country', 'quote.client.country', 'quote.company')->each(function ($invitation) use ($reminder_template) {
EmailEntity::dispatch($invitation, $this->quote->company, $reminder_template);

View File

@ -77,8 +77,6 @@ class SubscriptionService
$recurring_invoice_repo = new RecurringInvoiceRepository();
$recurring_invoice = $recurring_invoice_repo->save([], $recurring_invoice);
// $recurring_invoice->next_send_date = now()->format('Y-m-d');
// $recurring_invoice->next_send_date = $recurring_invoice->nextSendDate();
$recurring_invoice->auto_bill = $this->subscription->auto_bill;
/* Start the recurring service */
@ -87,7 +85,6 @@ class SubscriptionService
->save();
//execute any webhooks
$context = [
'context' => 'recurring_purchase',
'recurring_invoice' => $recurring_invoice->hashed_id,
@ -95,6 +92,7 @@ class SubscriptionService
'client' => $recurring_invoice->client->hashed_id,
'subscription' => $this->subscription->hashed_id,
'contact' => auth('contact')->user()->hashed_id,
'account_key' => $recurring_invoice->client->custom_value2,
];
$response = $this->triggerWebhook($context);
@ -111,6 +109,7 @@ class SubscriptionService
'invoice' => $this->encodePrimaryKey($payment_hash->fee_invoice_id),
'client' => $invoice->client->hashed_id,
'subscription' => $this->subscription->hashed_id,
'account_key' => $invoice->client->custom_value2,
];
//execute any webhooks
@ -130,6 +129,7 @@ class SubscriptionService
'contact' => $contact->hashed_id,
'contact_email' => $contact->email,
'client' => $contact->client->hashed_id,
'account_key' => $contact->client->custom_value2,
];
$response = $this->triggerWebhook($context);
@ -180,6 +180,7 @@ class SubscriptionService
'recurring_invoice' => $recurring_invoice->hashed_id,
'client' => $recurring_invoice->client->hashed_id,
'subscription' => $this->subscription->hashed_id,
'account_key' => $recurring_invoice->client->custom_value2,
];
//execute any webhooks
@ -452,6 +453,7 @@ class SubscriptionService
'client' => $new_recurring_invoice->client->hashed_id,
'subscription' => $target_subscription->hashed_id,
'contact' => auth('contact')->user()->hashed_id,
'account_key' => $new_recurring_invoice->client->custom_value2,
];
$response = $this->triggerWebhook($context);
@ -572,6 +574,7 @@ class SubscriptionService
'client' => $recurring_invoice->client->hashed_id,
'subscription' => $this->subscription->hashed_id,
'contact' => auth('contact')->user()->hashed_id,
'account_key' => $recurring_invoice->client->custom_value2,
];
@ -768,8 +771,6 @@ class SubscriptionService
$response = false;
$body = array_merge($context, [
'company_key' => $this->subscription->company->company_key,
'account_key' => $this->subscription->company->account->key,
'db' => $this->subscription->company->db,
]);
@ -921,6 +922,7 @@ class SubscriptionService
'recurring_invoice' => $recurring_invoice->hashed_id,
'client' => $recurring_invoice->client->hashed_id,
'contact' => auth('contact')->user()->hashed_id,
'account_key' => $recurring_invoice->client->custom_value2,
];
$this->triggerWebhook($context);
@ -1043,6 +1045,7 @@ class SubscriptionService
'client' => $invoice->client->hashed_id,
'contact' => $invoice->client->primary_contact()->first() ? $invoice->client->primary_contact()->first()->hashed_id: $invoice->client->contacts->first()->hashed_id,
'invoice' => $invoice->hashed_id,
'account_key' => $invoice->client->custom_value2,
];
$response = $this->triggerWebhook($context);

671
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -113,7 +113,7 @@
table-layout: fixed;
overflow-wrap: break-word;
margin-top: 3rem;
margin-bottom: 200px;
margin-bottom: 0px;
}
[data-ref="table"]:last-child{
@ -371,20 +371,24 @@
$entity_images
<div id="footer">
<div>
<div style="width: 100%;">
<p data-ref="total_table-footer">$entity_footer</p>
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table', 'statement-invoice-table-totals', 'statement-payment-table-totals','statement-invoice-table-totals',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table', 'statement-aging-table-totals', 'statement-payment-table-totals'
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table'
];
tables.forEach((tableIdentifier) => {
const el =document.getElementById(tableIdentifier);
if(el && el.childElementCount === 0)el.remove()
console.log(document.getElementById(tableIdentifier));
document.getElementById(tableIdentifier)?.childElementCount === 0
? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important')
: '';
});
});
</script>

View File

@ -351,7 +351,7 @@ $entity_images
<div class="repeating-footer" id="footer">
<p data-ref="total_table-footer">$entity_footer</p>
</div>
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
@ -368,3 +368,5 @@ $entity_images
});
});
</script>
</div>

View File

@ -313,20 +313,25 @@ $entity_images
<div class="repeating-footer" id="footer">
<p data-ref="total_table-footer">$entity_footer</p>
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table'
];
tables.forEach((tableIdentifier) => {
console.log(document.getElementById(tableIdentifier));
document.getElementById(tableIdentifier)?.childElementCount === 0
? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important')
: '';
});
});
</script>
</div>
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';
});
});
</script>

View File

@ -303,24 +303,29 @@
<div class="repeating-header" id="header"></div>
<div class="repeating-footer" id="footer">
<p data-ref="total_table-footer">$entity_footer</p>
</div>
$entity_images
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
<div class="repeating-footer" id="footer">
<p data-ref="total_table-footer">$entity_footer</p>
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';
});
});
</script>
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table'
];
tables.forEach((tableIdentifier) => {
console.log(document.getElementById(tableIdentifier));
document.getElementById(tableIdentifier)?.childElementCount === 0
? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important')
: '';
});
});
</script>
</div>

View File

@ -313,24 +313,30 @@
<div class="repeating-header" id="header"></div>
<div class="repeating-footer" id="footer">
<p data-ref="total_table-footer">$entity_footer</p>
</div>
$entity_images
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
<div class="repeating-footer" id="footer">
<p data-ref="total_table-footer">$entity_footer</p>
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table'
];
tables.forEach((tableIdentifier) => {
console.log(document.getElementById(tableIdentifier));
document.getElementById(tableIdentifier)?.childElementCount === 0
? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important')
: '';
});
});
</script>
</div>
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';
});
});
</script>

View File

@ -354,30 +354,29 @@
<div class="repeating-header" id="header"></div>
<div class="repeating-footer" id="footer">
<p data-ref="total_table-footer">$entity_footer</p>
</div>
$entity_images
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
<div class="repeating-footer" id="footer">
<p data-ref="total_table-footer">$entity_footer</p>
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';
});
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table'
];
tables.forEach((tableIdentifier) => {
console.log(document.getElementById(tableIdentifier));
document.getElementById(tableIdentifier)?.childElementCount === 0
? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important')
: '';
});
});
</script>
</div>
// If we have elements in these tables, we can change label to "Statement" & hide entity details.
if (document.querySelectorAll('#statement-payment-table > tbody, #statement-payment-table > tbody, #statement-aging-table-totals > tbody').length > 0) {
document.querySelector('.entity-label').innerText = '$statement_label';
document.querySelector('.entity-details-wrapper').style.display = 'none';
}
});
</script>

View File

@ -348,24 +348,28 @@ $entity_images
<div id="footer">
<div class="footer-content">
<div style="width: 70%;">
<div style="width: 90%">
<p data-ref="total_table-footer">$entity_footer</p>
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table', 'statement-invoice-table-totals', 'statement-payment-table-totals','statement-invoice-table-totals',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table', 'statement-aging-table-totals', 'statement-payment-table-totals'
];
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table'
];
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).remove()
: '';
});
tables.forEach((tableIdentifier) => {
console.log(document.getElementById(tableIdentifier));
document.getElementById(tableIdentifier)?.childElementCount === 0
? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important')
: '';
});
</script>
});
</script>
</div>
<div class="footer-company-details-address-wrapper">
<div id="company-details"></div>

View File

@ -288,24 +288,27 @@
<div class="repeating-header" id="header"></div>
<div class="repeating-footer" id="footer">
<p data-ref="total_table-footer">$entity_footer</p>
</div>
$entity_images
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
<div class="repeating-footer" id="footer">
<p data-ref="total_table-footer">$entity_footer</p>
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';
});
});
</script>
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table'
];
tables.forEach((tableIdentifier) => {
console.log(document.getElementById(tableIdentifier));
document.getElementById(tableIdentifier)?.childElementCount === 0
? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important')
: '';
});
});
</script>
</div>

View File

@ -390,21 +390,23 @@ $entity_images
<div style="background-color: #F8B300"><!-- 7 --></div>
<div style="background-color: #009B8F"><!-- 8 --></div>
</div>
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table'
];
tables.forEach((tableIdentifier) => {
console.log(document.getElementById(tableIdentifier));
document.getElementById(tableIdentifier)?.childElementCount === 0
? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important')
: '';
});
});
</script>
</div>
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';
});
});
</script>

View File

@ -353,24 +353,29 @@
<div class="repeating-header" id="header"></div>
<div class="repeating-footer" id="footer">
<p data-ref="total_table-footer">$entity_footer</p>
</div>
$entity_images
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
<div class="repeating-footer" id="footer">
<p data-ref="total_table-footer">$entity_footer</p>
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table'
];
tables.forEach((tableIdentifier) => {
console.log(document.getElementById(tableIdentifier));
document.getElementById(tableIdentifier)?.childElementCount === 0
? document.getElementById(tableIdentifier).style.setProperty('display', 'none', 'important')
: '';
});
});
</script>
</div>
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';
});
});
</script>

View File

@ -12,12 +12,6 @@
{{ ctrans('texts.credits') }}
</button>
<button
class="button border border-transparent hover:border-gray-600 {{ $tab === 'expenses' ? 'border-gray-600' : '' }}"ž
wire:click="updateResources('expenses')" />
{{ ctrans('texts.expenses') }}
</button>
<button
class="button border border-transparent hover:border-gray-600 {{ $tab === 'invoices' ? 'border-gray-600' : '' }}"ž
wire:click="updateResources('invoices')" />

View File

@ -110,14 +110,14 @@
document.getElementById('handlePlanChange').addEventListener('click', function() {
if(document.getElementById("newPlan").value.length > 1)
location.href = 'https://invoiceninja.invoicing.co/client/subscriptions/{{ $current_recurring_id }}/plan_switch/' + document.getElementById("newPlan").value + '';
location.href = 'http://devhosted.test:8000/client/subscriptions/{{ $current_recurring_id }}/plan_switch/' + document.getElementById("newPlan").value + '';
});
@else
document.getElementById('handleNewPlan').addEventListener('click', function() {
if(document.getElementById("newPlan").value.length > 1)
location.href = 'https://invoiceninja.invoicing.co/client/subscriptions/' + document.getElementById("newPlan").value + '/purchase';
location.href = 'http://devhosted.test:8000/client/subscriptions/' + document.getElementById("newPlan").value + '/purchase';
});
@endif

View File

@ -121,6 +121,17 @@ class ExpenseApiTest extends TestCase
$response->assertStatus(200);
}
public function testExpenseGetSort()
{
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->get('/api/v1/expenses?sort=public_notes|desc');
$response->assertStatus(200);
}
public function testExpenseNotArchived()
{
$response = $this->withHeaders([

View File

@ -38,7 +38,7 @@ class AutoBillInvoiceTest extends TestCase
$this->assertEquals($this->client->paid_to_date, 0);
$this->assertEquals($this->client->credit_balance, 10);
$this->invoice->service()->markSent()->autoBill()->save();
$this->invoice->service()->markSent()->autoBill();
$this->assertNotNull($this->invoice->payments());
$this->assertEquals(10, $this->invoice->payments()->sum('payments.amount'));

View File

@ -94,13 +94,13 @@ class SubscriptionsCalcTest extends TestCase
$refund = $pro_rata->refund($invoice->amount, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-06'), $subscription->frequency_id);
$this->assertEquals(1.67, $refund);
$this->assertEquals(1.61, $refund);
$pro_rata = new ProRata;
$upgrade = $pro_rata->charge($target->price, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-06'), $subscription->frequency_id);
$this->assertEquals(3.33, $upgrade);
$this->assertEquals(3.23, $upgrade);
}
}