mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-07 15:34:39 -04:00
Merge remote-tracking branch 'upstream/v5-develop' into browser-pay
This commit is contained in:
commit
e1590af4cf
@ -99,7 +99,7 @@ class CheckData extends Command
|
|||||||
config(['database.default' => $database]);
|
config(['database.default' => $database]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->checkInvoiceBalances();
|
// $this->checkInvoiceBalances();
|
||||||
$this->checkInvoicePayments();
|
$this->checkInvoicePayments();
|
||||||
$this->checkPaidToDates();
|
$this->checkPaidToDates();
|
||||||
// $this->checkPaidToCompanyDates();
|
// $this->checkPaidToCompanyDates();
|
||||||
@ -406,6 +406,79 @@ class CheckData extends Command
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
// }
|
// }
|
||||||
|
private function clientPaidToDateQuery()
|
||||||
|
{
|
||||||
|
$results = \DB::select( \DB::raw("
|
||||||
|
SELECT
|
||||||
|
clients.id as client_id,
|
||||||
|
clients.paid_to_date as client_paid_to_date,
|
||||||
|
SUM(coalesce(payments.amount - payments.refunded,0)) as payments_applied
|
||||||
|
FROM clients
|
||||||
|
INNER JOIN
|
||||||
|
payments ON
|
||||||
|
clients.id=payments.client_id
|
||||||
|
WHERE payments.status_id IN (1,4,5,6)
|
||||||
|
AND clients.is_deleted = false
|
||||||
|
AND payments.is_deleted = false
|
||||||
|
GROUP BY clients.id
|
||||||
|
HAVING payments_applied != client_paid_to_date
|
||||||
|
ORDER BY clients.id;
|
||||||
|
") );
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function clientCreditPaymentables($client)
|
||||||
|
{
|
||||||
|
$results = \DB::select( \DB::raw("
|
||||||
|
SELECT
|
||||||
|
SUM(paymentables.amount - paymentables.refunded) as credit_payment
|
||||||
|
FROM payments
|
||||||
|
LEFT JOIN paymentables
|
||||||
|
ON
|
||||||
|
payments.id = paymentables.payment_id
|
||||||
|
WHERE paymentable_type = 'App\\Models\\Credit'
|
||||||
|
AND paymentables.deleted_at is NULL
|
||||||
|
AND payments.client_id = 85;
|
||||||
|
") );
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkPaidToDatesNew()
|
||||||
|
{
|
||||||
|
$clients_to_check = $this->clientPaidToDateQuery();
|
||||||
|
|
||||||
|
$this->wrong_paid_to_dates = 0;
|
||||||
|
|
||||||
|
foreach($clients_to_check as $_client)
|
||||||
|
{
|
||||||
|
$client = Client::find($_client['client_id']);
|
||||||
|
|
||||||
|
$credits_used_for_payments = $this->clientCreditPaymentables($client);
|
||||||
|
|
||||||
|
$total_paid_to_date = $_client['payments_applied'] + $credits_used_for_payments['credit_payment'];
|
||||||
|
|
||||||
|
if(round($total_paid_to_date,2) != round($_client['client_paid_to_date'],2)){
|
||||||
|
|
||||||
|
$this->wrong_paid_to_dates++;
|
||||||
|
|
||||||
|
$this->logMessage($client->present()->name.' id = # '.$client->id." - Paid to date does not match Client Paid To Date = {$client->paid_to_date} - Invoice Payments = {$total_paid_to_date}");
|
||||||
|
|
||||||
|
$this->isValid = false;
|
||||||
|
|
||||||
|
if($this->option('paid_to_date')){
|
||||||
|
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." Fixing {$client->paid_to_date} to {$total_paid_to_date}");
|
||||||
|
$client->paid_to_date = $total_paid_to_date;
|
||||||
|
$client->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private function checkPaidToDates()
|
private function checkPaidToDates()
|
||||||
{
|
{
|
||||||
@ -496,8 +569,6 @@ class CheckData extends Command
|
|||||||
->pluck('p')
|
->pluck('p')
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
// $total_paid = $total_amount - $total_refund;
|
|
||||||
|
|
||||||
$total_credit = $invoice->credits()->get()->sum('amount');
|
$total_credit = $invoice->credits()->get()->sum('amount');
|
||||||
|
|
||||||
$calculated_paid_amount = $invoice->amount - $invoice->balance - $total_credit;
|
$calculated_paid_amount = $invoice->amount - $invoice->balance - $total_credit;
|
||||||
@ -543,7 +614,32 @@ class CheckData extends Command
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private function clientBalanceQuery()
|
||||||
|
{
|
||||||
|
$results = \DB::select( \DB::raw("
|
||||||
|
SELECT
|
||||||
|
SUM(invoices.balance) as invoice_balance,
|
||||||
|
SUM(credits.balance) as credit_balance,
|
||||||
|
clients.id as client_id,
|
||||||
|
clients.balance as client_balance
|
||||||
|
FROM invoices
|
||||||
|
INNER JOIN
|
||||||
|
clients ON
|
||||||
|
clients.id=invoices.client_id
|
||||||
|
INNER JOIN
|
||||||
|
credits ON
|
||||||
|
credits.client_id = clients.id
|
||||||
|
WHERE invoices.is_deleted = false
|
||||||
|
AND invoices.status_id > 1
|
||||||
|
AND credits.is_deleted = false
|
||||||
|
AND credits.status_id > 1
|
||||||
|
GROUP BY clients.id
|
||||||
|
HAVING invoice_balance != clients.balance
|
||||||
|
ORDER BY clients.id;
|
||||||
|
") );
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -553,26 +649,62 @@ class CheckData extends Command
|
|||||||
$this->wrong_balances = 0;
|
$this->wrong_balances = 0;
|
||||||
$this->wrong_paid_to_dates = 0;
|
$this->wrong_paid_to_dates = 0;
|
||||||
|
|
||||||
foreach (Client::cursor()->where('is_deleted', 0)->where('clients.updated_at', '>', now()->subDays(2)) as $client) {
|
$clients = $this->clientBalanceQuery();
|
||||||
//$invoice_balance = $client->invoices->where('is_deleted', false)->where('status_id', '>', 1)->sum('balance');
|
|
||||||
$invoice_balance = Invoice::where('client_id', $client->id)->where('is_deleted', false)->where('status_id', '>', 1)->withTrashed()->sum('balance');
|
|
||||||
$credit_balance = Credit::where('client_id', $client->id)->where('is_deleted', false)->withTrashed()->sum('balance');
|
|
||||||
|
|
||||||
/*Legacy - V4 will add credits to the balance - we may need to reverse engineer this and remove the credits from the client balance otherwise we need this hack here and in the invoice balance check.*/
|
foreach($clients as $client)
|
||||||
if($client->balance != $invoice_balance)
|
{
|
||||||
$invoice_balance -= $credit_balance;
|
$client = (array)$client;
|
||||||
|
|
||||||
|
$invoice_balance = $client['invoice_balance'] - $client['credit_balance'];
|
||||||
|
|
||||||
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
|
$ledger = CompanyLedger::where('client_id', $client['client_id'])->orderBy('id', 'DESC')->first();
|
||||||
|
|
||||||
if ($ledger && (string) $invoice_balance != (string) $client->balance) {
|
if ($ledger && (string) $invoice_balance != (string) $client['client_balance']) {
|
||||||
$this->wrong_paid_to_dates++;
|
$this->wrong_paid_to_dates++;
|
||||||
$this->logMessage($client->present()->name.' - '.$client->id." - calculated client balances do not match Invoice Balances = {$invoice_balance} - Client Balance = ".rtrim($client->balance, '0'). " Ledger balance = {$ledger->balance}");
|
|
||||||
|
|
||||||
$this->isValid = false;
|
$client_object = Client::find($client['client_id']);
|
||||||
|
|
||||||
|
$this->logMessage($client_object->present()->name.' - '.$client_object->id." - calculated client balances do not match Invoice Balances = {$invoice_balance} - Client Balance = ".rtrim($client['client_balance'], '0'). " Ledger balance = {$ledger->balance}");
|
||||||
|
|
||||||
|
|
||||||
|
if($this->option('client_balance')){
|
||||||
|
|
||||||
|
$this->logMessage("# {$client_object->id} " . $client_object->present()->name.' - '.$client_object->number." Fixing {$client_object->balance} to {$invoice_balance}");
|
||||||
|
$client->balance = $invoice_balance;
|
||||||
|
$client->save();
|
||||||
|
|
||||||
|
$ledger->adjustment = $invoice_balance;
|
||||||
|
$ledger->balance = $invoice_balance;
|
||||||
|
$ledger->notes = 'Ledger Adjustment';
|
||||||
|
$ledger->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$this->isValid = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// foreach (Client::cursor()->where('is_deleted', 0)->where('clients.updated_at', '>', now()->subDays(2)) as $client) {
|
||||||
|
|
||||||
|
// $invoice_balance = Invoice::where('client_id', $client->id)->where('is_deleted', false)->where('status_id', '>', 1)->withTrashed()->sum('balance');
|
||||||
|
// $credit_balance = Credit::where('client_id', $client->id)->where('is_deleted', false)->withTrashed()->sum('balance');
|
||||||
|
|
||||||
|
// if($client->balance != $invoice_balance)
|
||||||
|
// $invoice_balance -= $credit_balance;
|
||||||
|
|
||||||
|
// $ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
|
||||||
|
|
||||||
|
// if ($ledger && (string) $invoice_balance != (string) $client->balance) {
|
||||||
|
// $this->wrong_paid_to_dates++;
|
||||||
|
// $this->logMessage($client->present()->name.' - '.$client->id." - calculated client balances do not match Invoice Balances = {$invoice_balance} - Client Balance = ".rtrim($client->balance, '0'). " Ledger balance = {$ledger->balance}");
|
||||||
|
|
||||||
|
// $this->isValid = false;
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
$this->logMessage("{$this->wrong_paid_to_dates} clients with incorrect client balances");
|
$this->logMessage("{$this->wrong_paid_to_dates} clients with incorrect client balances");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,12 +213,18 @@ abstract class QueryFilters
|
|||||||
public function with_trashed($value)
|
public function with_trashed($value)
|
||||||
{
|
{
|
||||||
|
|
||||||
if($value == 'true'){
|
if($value == 'false'){
|
||||||
|
|
||||||
$this->builder->withTrashed();
|
return $this->builder->where('is_deleted', 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if($value == 'true'){
|
||||||
|
|
||||||
|
// $this->builder->withTrashed();
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
return $this->builder;
|
return $this->builder;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,9 @@ class TokenController extends BaseController
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
$this->token_repo = $token_repo;
|
$this->token_repo = $token_repo;
|
||||||
|
|
||||||
|
$this->middleware('password_protected')->only(['store','update']);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,6 +13,7 @@ namespace App\Http\Requests\Client;
|
|||||||
|
|
||||||
use App\DataMapper\ClientSettings;
|
use App\DataMapper\ClientSettings;
|
||||||
use App\Http\Requests\Request;
|
use App\Http\Requests\Request;
|
||||||
|
use App\Http\ValidationRules\Client\CountryCodeExistsRule;
|
||||||
use App\Http\ValidationRules\Ninja\CanStoreClientsRule;
|
use App\Http\ValidationRules\Ninja\CanStoreClientsRule;
|
||||||
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
|
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
@ -51,6 +52,14 @@ class StoreClientRequest extends Request
|
|||||||
$rules['number'] = Rule::unique('clients')->where('company_id', auth()->user()->company()->id);
|
$rules['number'] = Rule::unique('clients')->where('company_id', auth()->user()->company()->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isset($this->currency_code)){
|
||||||
|
$rules['currency_code'] = 'sometimes|exists:currencies,code';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($this->country_code)){
|
||||||
|
$rules['country_code'] = new CountryCodeExistsRule();
|
||||||
|
}
|
||||||
|
|
||||||
/* Ensure we have a client name, and that all emails are unique*/
|
/* Ensure we have a client name, and that all emails are unique*/
|
||||||
//$rules['name'] = 'required|min:1';
|
//$rules['name'] = 'required|min:1';
|
||||||
$rules['settings'] = new ValidClientGroupSettingsRule();
|
$rules['settings'] = new ValidClientGroupSettingsRule();
|
||||||
@ -133,6 +142,7 @@ class StoreClientRequest extends Request
|
|||||||
// 'unique' => ctrans('validation.unique', ['attribute' => ['email','number']),
|
// 'unique' => ctrans('validation.unique', ['attribute' => ['email','number']),
|
||||||
//'required' => trans('validation.required', ['attribute' => 'email']),
|
//'required' => trans('validation.required', ['attribute' => 'email']),
|
||||||
'contacts.*.email.required' => ctrans('validation.email', ['attribute' => 'email']),
|
'contacts.*.email.required' => ctrans('validation.email', ['attribute' => 'email']),
|
||||||
|
'currency_code' => 'Currency code does not exist',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,6 +168,9 @@ class StoreClientRequest extends Request
|
|||||||
return $item->code == $code;
|
return $item->code == $code;
|
||||||
})->first();
|
})->first();
|
||||||
|
|
||||||
return (string) $currency->id;
|
if($currency)
|
||||||
|
return (string) $currency->id;
|
||||||
|
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
60
app/Http/ValidationRules/Client/CountryCodeExistsRule.php
Normal file
60
app/Http/ValidationRules/Client/CountryCodeExistsRule.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Credit Ninja (https://creditninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/creditninja/creditninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Credit Ninja LLC (https://creditninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\ValidationRules\Client;
|
||||||
|
|
||||||
|
use App\Models\Country;
|
||||||
|
use Illuminate\Contracts\Validation\Rule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UniqueCreditNumberRule.
|
||||||
|
*/
|
||||||
|
class CountryCodeExistsRule implements Rule
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $attribute
|
||||||
|
* @param mixed $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function passes($attribute, $value)
|
||||||
|
{
|
||||||
|
return $this->checkIfCodeExists($value); //if it exists, return false!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function message()
|
||||||
|
{
|
||||||
|
return 'Country code does not exist';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function checkIfCodeExists($value) : bool
|
||||||
|
{
|
||||||
|
$country = Country::where('iso_3166_2', $value)
|
||||||
|
->orWhere('iso_3166_3', $value)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($country)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -1032,10 +1032,12 @@ class CompanyImport implements ShouldQueue
|
|||||||
unset($user_array['hashed_id']);
|
unset($user_array['hashed_id']);
|
||||||
unset($user_array['id']);
|
unset($user_array['id']);
|
||||||
|
|
||||||
$new_user = User::firstOrNew(
|
/*Make sure we are searching for archived users also and restore if we find them.*/
|
||||||
|
|
||||||
|
$new_user = User::withTrashed()->firstOrNew(
|
||||||
['email' => $user->email],
|
['email' => $user->email],
|
||||||
$user_array,
|
$user_array,
|
||||||
);
|
)->restore();
|
||||||
|
|
||||||
$new_user->account_id = $this->account->id;
|
$new_user->account_id = $this->account->id;
|
||||||
$new_user->save(['timestamps' => false]);
|
$new_user->save(['timestamps' => false]);
|
||||||
@ -1062,10 +1064,10 @@ class CompanyImport implements ShouldQueue
|
|||||||
unset($cu_array['company_id']);
|
unset($cu_array['company_id']);
|
||||||
unset($cu_array['user_id']);
|
unset($cu_array['user_id']);
|
||||||
|
|
||||||
$new_cu = CompanyUser::firstOrNew(
|
$new_cu = CompanyUser::withTrashed()->firstOrNew(
|
||||||
['user_id' => $user_id, 'company_id' => $this->company->id],
|
['user_id' => $user_id, 'company_id' => $this->company->id],
|
||||||
$cu_array,
|
$cu_array,
|
||||||
);
|
)->restore();
|
||||||
|
|
||||||
$new_cu->account_id = $this->account->id;
|
$new_cu->account_id = $this->account->id;
|
||||||
$new_cu->save(['timestamps' => false]);
|
$new_cu->save(['timestamps' => false]);
|
||||||
|
@ -212,6 +212,8 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
|
|
||||||
$google->getClient()->setAccessToken(json_encode($user->oauth_user_token));
|
$google->getClient()->setAccessToken(json_encode($user->oauth_user_token));
|
||||||
|
|
||||||
|
//need to slow down gmail requests otherwise we hit 429's
|
||||||
|
sleep(1);
|
||||||
}
|
}
|
||||||
catch(\Exception $e) {
|
catch(\Exception $e) {
|
||||||
$this->logMailError('Gmail Token Invalid', $this->company->clients()->first());
|
$this->logMailError('Gmail Token Invalid', $this->company->clients()->first());
|
||||||
@ -225,9 +227,6 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
* just for this request.
|
* just for this request.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// config(['mail.driver' => 'gmail']);
|
|
||||||
// (new MailServiceProvider(app()))->register();
|
|
||||||
|
|
||||||
$token = $user->oauth_user_token->access_token;
|
$token = $user->oauth_user_token->access_token;
|
||||||
|
|
||||||
$this->nmo
|
$this->nmo
|
||||||
|
@ -530,7 +530,7 @@ class Client extends BaseModel implements HasLocalePreference
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->country->iso_3166_3 == 'GBR' && in_array(GatewayType::DIRECT_DEBIT, array_column($pms, 'gateway_type_id'))) {
|
if ($this->country && $this->country->iso_3166_3 == 'GBR' && in_array(GatewayType::DIRECT_DEBIT, array_column($pms, 'gateway_type_id'))) {
|
||||||
foreach ($pms as $pm) {
|
foreach ($pms as $pm) {
|
||||||
if ($pm['gateway_type_id'] == GatewayType::DIRECT_DEBIT) {
|
if ($pm['gateway_type_id'] == GatewayType::DIRECT_DEBIT) {
|
||||||
$cg = CompanyGateway::find($pm['company_gateway_id']);
|
$cg = CompanyGateway::find($pm['company_gateway_id']);
|
||||||
|
@ -30,7 +30,7 @@ class PaymentObserver
|
|||||||
->exists();
|
->exists();
|
||||||
|
|
||||||
if ($subscriptions) {
|
if ($subscriptions) {
|
||||||
WebhookHandler::dispatch(Webhook::EVENT_CREATE_PAYMENT, $payment, $payment->company, 'invoices');
|
WebhookHandler::dispatch(Webhook::EVENT_CREATE_PAYMENT, $payment, $payment->company, 'invoices,client');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ class PaymentObserver
|
|||||||
->exists();
|
->exists();
|
||||||
|
|
||||||
if ($subscriptions) {
|
if ($subscriptions) {
|
||||||
WebhookHandler::dispatch(Webhook::EVENT_DELETE_PAYMENT, $payment, $payment->company, 'invoices');
|
WebhookHandler::dispatch(Webhook::EVENT_DELETE_PAYMENT, $payment, $payment->company, 'invoices,client');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
public/css/app.css
vendored
2
public/css/app.css
vendored
File diff suppressed because one or more lines are too long
2
public/css/card-js.min.css
vendored
2
public/css/card-js.min.css
vendored
@ -1 +1 @@
|
|||||||
.card-js input.card-number{padding-right:48px}.card-js .card-number-wrapper .card-type-icon{height:23px;width:32px;position:absolute;display:block;right:8px;top:7px;background:url(https://cardjs.co.uk/img/cards.png) 0 23px no-repeat;pointer-events:none;opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-ms-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.card-js .card-number-wrapper .show{opacity:1}.card-js .card-number-wrapper .card-type-icon.visa{background-position:0 0}.card-js .card-number-wrapper .card-type-icon.master-card{background-position:-32px 0}.card-js .card-number-wrapper .card-type-icon.american-express{background-position:-64px 0}.card-js .card-number-wrapper .card-type-icon.discover{background-position:-96px 0}.card-js .card-number-wrapper .card-type-icon.diners{background-position:-128px 0}.card-js .card-number-wrapper .card-type-icon.jcb{background-position:-160px 0}.card-js .cvc-container{width:50%;float:right}.card-js .cvc-wrapper{box-sizing:border-box;margin-left:5px}.card-js .cvc-wrapper .cvc{display:block;width:100%}.card-js .expiry-container{width:50%;float:left}.card-js .expiry-wrapper{box-sizing:border-box;margin-right:5px}.card-js .expiry-wrapper .expiry{display:block;width:100%}.card-js .expiry-wrapper .expiry-month{border-top-right-radius:0;border-bottom-right-radius:0;padding-left:30px}.card-js .expiry-wrapper .expiry-year{border-top-left-radius:0;border-bottom-left-radius:0;border-left:0}.card-js .expiry-wrapper .expiry-month,.card-js .expiry-wrapper .expiry-year{display:inline-block}.card-js .expiry-wrapper .expiry{padding-left:38px}.card-js .icon{position:absolute;display:block;width:24px;height:17px;left:8px;top:10px;pointer-events:none}.card-js .icon.right{right:8px;left:auto}.card-js .icon.popup{cursor:pointer;pointer-events:auto}.card-js .icon .svg{fill:#888}.card-js .icon.popup .svg{fill:#aaa!important}.card-js .card-number-wrapper,.card-js .name-wrapper{margin-bottom:15px;width:100%}.card-js .card-number-wrapper,.card-js .cvc-wrapper,.card-js .expiry-wrapper,.card-js .name-wrapper{-webkit-box-shadow:0 1px 0 rgba(255,255,255,.7),inset 0 1px 0 rgba(255,255,255,.7);-moz-box-shadow:0 1px 0 rgba(255,255,255,.7),inset 0 1px 0 rgba(255,255,255,.7);-ms-box-shadow:0 1px 0 rgba(255,255,255,.7),inset 0 1px 0 rgba(255,255,255,.7);-o-box-shadow:0 1px 0 rgba(255,255,255,.7),inset 0 1px 0 rgba(255,255,255,.7);box-shadow:0 1px 0 rgba(255,255,255,.7),inset 0 1px 0 rgba(255,255,255,.7);position:relative}.card-js .card-number-wrapper,.card-js .cvc-container,.card-js .expiry-container,.card-js .name-wrapper{display:inline-block}.card-js::after{content:' ';display:table;clear:both}.card-js input,.card-js select{color:#676767;font-size:15px;font-weight:300;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;height:36px;border:1px solid #d9d9d9;border-radius:4px;box-shadow:none;background-color:#fdfdfd;box-sizing:border-box;padding:0;-webkit-transition:border-color .15s linear,box-shadow .15s linear;-moz-transition:border-color .15s linear,box-shadow .15s linear;-ms-transition:border-color .15s linear,box-shadow .15s linear;-o-transition:border-color .15s linear,box-shadow .15s linear;transition:border-color .15s linear,box-shadow .15s linear}.card-js select{-moz-appearance:none;text-indent:.01px;text-overflow:''}.card-js input[disabled],.card-js select[disabled]{background-color:#eee;color:#555}.card-js select option[hidden]{color:#aba9a9}.card-js input:focus,.card-js select:focus{background-color:#fff;outline:0;border-color:#66afe9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.card-js input[readonly=readonly]:not([disabled]),.card-js input[readonly]:not([disabled]){background-color:#fff;cursor:pointer}.card-js .has-error input,.card-js .has-error input:focus{border-color:#f64b2f;box-shadow:none}.card-js input.card-number,.card-js input.cvc,.card-js input.name{padding-left:38px;width:100%}.card-js.stripe .icon .svg{fill:#559A28}
|
.card-js input.card-number{padding-right:48px}.card-js .card-number-wrapper .card-type-icon{height:23px;width:32px;position:absolute;display:block;right:8px;top:7px;background:url(https://cardjs.co.uk/img/cards.png) 0 23px no-repeat;pointer-events:none;opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-ms-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.card-js .card-number-wrapper .show{opacity:1}.card-js .card-number-wrapper .card-type-icon.visa{background-position:0 0}.card-js .card-number-wrapper .card-type-icon.master-card{background-position:-32px 0}.card-js .card-number-wrapper .card-type-icon.american-express{background-position:-64px 0}.card-js .card-number-wrapper .card-type-icon.discover{background-position:-96px 0}.card-js .card-number-wrapper .card-type-icon.diners{background-position:-128px 0}.card-js .card-number-wrapper .card-type-icon.jcb{background-position:-160px 0}.card-js .cvc-container{width:50%;float:right}.card-js .cvc-wrapper{box-sizing:border-box;margin-left:5px}.card-js .cvc-wrapper .cvc{display:block;width:100%}.card-js .expiry-container{width:50%;float:left}.card-js .expiry-wrapper{box-sizing:border-box;margin-right:5px}.card-js .expiry-wrapper .expiry{display:block;width:100%}.card-js .expiry-wrapper .expiry-month{border-top-right-radius:0;border-bottom-right-radius:0;padding-left:30px}.card-js .expiry-wrapper .expiry-year{border-top-left-radius:0;border-bottom-left-radius:0;border-left:0}.card-js .expiry-wrapper .expiry-month,.card-js .expiry-wrapper .expiry-year{display:inline-block}.card-js .expiry-wrapper .expiry{padding-left:38px}.card-js .icon{position:absolute;display:block;width:24px;height:17px;left:8px;top:10px;pointer-events:none}.card-js .icon.right{right:8px;left:auto}.card-js .icon.popup{cursor:pointer;pointer-events:auto}.card-js .icon .svg{fill:#888}.card-js .icon.popup .svg{fill:#aaa!important}.card-js .card-number-wrapper,.card-js .name-wrapper{margin-bottom:15px;width:100%}.card-js .card-number-wrapper,.card-js .cvc-wrapper,.card-js .expiry-wrapper,.card-js .name-wrapper{-webkit-box-shadow:0 1px 0 rgba(255,255,255,.7),inset 0 1px 0 rgba(255,255,255,.7);-moz-box-shadow:0 1px 0 rgba(255,255,255,.7),inset 0 1px 0 rgba(255,255,255,.7);-ms-box-shadow:0 1px 0 rgba(255,255,255,.7),inset 0 1px 0 rgba(255,255,255,.7);-o-box-shadow:0 1px 0 rgba(255,255,255,.7),inset 0 1px 0 rgba(255,255,255,.7);box-shadow:0 1px 0 rgba(255,255,255,.7),inset 0 1px 0 rgba(255,255,255,.7);position:relative}.card-js .card-number-wrapper,.card-js .cvc-container,.card-js .expiry-container,.card-js .name-wrapper{display:inline-block}.card-js::after{content:' ';display:table;clear:both}.card-js input,.card-js select{color:#676767;font-size:15px;font-weight:300;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;height:36px;border:1px solid #d9d9d9;border-radius:4px;box-shadow:none;background-color:#FDFDFD;box-sizing:border-box;padding:0;-webkit-transition:border-color .15s linear,box-shadow .15s linear;-moz-transition:border-color .15s linear,box-shadow .15s linear;-ms-transition:border-color .15s linear,box-shadow .15s linear;-o-transition:border-color .15s linear,box-shadow .15s linear;transition:border-color .15s linear,box-shadow .15s linear}.card-js select{-moz-appearance:none;text-indent:.01px;text-overflow:''}.card-js input[disabled],.card-js select[disabled]{background-color:#eee;color:#555}.card-js select option[hidden]{color:#ABA9A9}.card-js input:focus,.card-js select:focus{background-color:#fff;outline:0;border-color:#66afe9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.card-js input[readonly=readonly]:not([disabled]),.card-js input[readonly]:not([disabled]){background-color:#fff;cursor:pointer}.card-js .has-error input,.card-js .has-error input:focus{border-color:#F64B2F;box-shadow:none}.card-js input.card-number,.card-js input.cvc,.card-js input.name{padding-left:38px;width:100%}.card-js.stripe .icon .svg{fill:#559A28}
|
6
public/flutter_service_worker.js
vendored
6
public/flutter_service_worker.js
vendored
@ -3,7 +3,7 @@ const MANIFEST = 'flutter-app-manifest';
|
|||||||
const TEMP = 'flutter-temp-cache';
|
const TEMP = 'flutter-temp-cache';
|
||||||
const CACHE_NAME = 'flutter-app-cache';
|
const CACHE_NAME = 'flutter-app-cache';
|
||||||
const RESOURCES = {
|
const RESOURCES = {
|
||||||
"version.json": "27abc97e9c76cf112b697fa080c304b5",
|
"version.json": "3930722e1581f582eefe59c75ab50c99",
|
||||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
||||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||||
"assets/fonts/MaterialIcons-Regular.otf": "4e6447691c9509f7acdbf8a931a85ca1",
|
"assets/fonts/MaterialIcons-Regular.otf": "4e6447691c9509f7acdbf8a931a85ca1",
|
||||||
@ -32,9 +32,9 @@ const RESOURCES = {
|
|||||||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "174c02fc4609e8fc4389f5d21f16a296",
|
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "174c02fc4609e8fc4389f5d21f16a296",
|
||||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
||||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||||
"main.dart.js": "9331fefe016a4110385aae52ece5bb7c",
|
"main.dart.js": "c2610220ba3a55e358c3c653d6242d0f",
|
||||||
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
|
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
|
||||||
"/": "3a8fb0769c1c1df7d1a95d627a2e2857"
|
"/": "b8da32f39d55fc73f8a721a7e141bbc1"
|
||||||
};
|
};
|
||||||
|
|
||||||
// The application shell files that are downloaded before a service worker can
|
// The application shell files that are downloaded before a service worker can
|
||||||
|
2
public/js/clients/shared/pdf.js
vendored
2
public/js/clients/shared/pdf.js
vendored
File diff suppressed because one or more lines are too long
36361
public/main.dart.js
vendored
36361
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
36217
public/main.foss.dart.js
vendored
36217
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
34465
public/main.html.dart.js
vendored
34465
public/main.html.dart.js
vendored
File diff suppressed because one or more lines are too long
41631
public/main.next.dart.js
vendored
41631
public/main.next.dart.js
vendored
File diff suppressed because one or more lines are too long
213
public/main.profile.dart.js
vendored
213
public/main.profile.dart.js
vendored
File diff suppressed because one or more lines are too long
@ -13,7 +13,7 @@
|
|||||||
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=ea4250be693260798735",
|
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=ea4250be693260798735",
|
||||||
"/js/setup/setup.js": "/js/setup/setup.js?id=6b870beeb350d83668c5",
|
"/js/setup/setup.js": "/js/setup/setup.js?id=6b870beeb350d83668c5",
|
||||||
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=8ce33c3deae058ad314f",
|
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=8ce33c3deae058ad314f",
|
||||||
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=8dc6dd2bab2a56bc86bb",
|
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=73a0d914ad3577f257f4",
|
||||||
"/js/clients/shared/multiple-downloads.js": "/js/clients/shared/multiple-downloads.js?id=c2caa29f753ad1f3a12c",
|
"/js/clients/shared/multiple-downloads.js": "/js/clients/shared/multiple-downloads.js?id=c2caa29f753ad1f3a12c",
|
||||||
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=448d055fa1e8357130e6",
|
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=448d055fa1e8357130e6",
|
||||||
"/js/clients/payments/braintree-credit-card.js": "/js/clients/payments/braintree-credit-card.js?id=a334dd9257dd510a1feb",
|
"/js/clients/payments/braintree-credit-card.js": "/js/clients/payments/braintree-credit-card.js?id=a334dd9257dd510a1feb",
|
||||||
@ -36,7 +36,6 @@
|
|||||||
"/js/clients/payments/stripe-eps.js": "/js/clients/payments/stripe-eps.js?id=1ed972f879869de66c8a",
|
"/js/clients/payments/stripe-eps.js": "/js/clients/payments/stripe-eps.js?id=1ed972f879869de66c8a",
|
||||||
"/js/clients/payments/stripe-ideal.js": "/js/clients/payments/stripe-ideal.js?id=73ce56676f9252b0cecf",
|
"/js/clients/payments/stripe-ideal.js": "/js/clients/payments/stripe-ideal.js?id=73ce56676f9252b0cecf",
|
||||||
"/js/clients/payments/stripe-przelewy24.js": "/js/clients/payments/stripe-przelewy24.js?id=f3a14f78bec8209c30ba",
|
"/js/clients/payments/stripe-przelewy24.js": "/js/clients/payments/stripe-przelewy24.js?id=f3a14f78bec8209c30ba",
|
||||||
"/js/clients/payments/stripe-browserpay.js": "/js/clients/payments/stripe-browserpay.js?id=71e49866d66a6d85b88a",
|
"/css/app.css": "/css/app.css?id=6d7f6103a3a7738d363b",
|
||||||
"/css/app.css": "/css/app.css?id=317a907834a0db9f8d41",
|
|
||||||
"/css/card-js.min.css": "/css/card-js.min.css?id=62afeb675235451543ad"
|
"/css/card-js.min.css": "/css/card-js.min.css?id=62afeb675235451543ad"
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
{"app_name":"invoiceninja_flutter","version":"5.0.62","build_number":"62"}
|
{"app_name":"invoiceninja_flutter","version":"5.0.63","build_number":"63"}
|
4
resources/js/clients/shared/pdf.js
vendored
4
resources/js/clients/shared/pdf.js
vendored
@ -15,11 +15,11 @@ class PDF {
|
|||||||
this.context = canvas.getContext('2d');
|
this.context = canvas.getContext('2d');
|
||||||
this.currentPage = 1;
|
this.currentPage = 1;
|
||||||
this.maxPages = 1;
|
this.maxPages = 1;
|
||||||
this.currentScale = 0.75;
|
this.currentScale = 1.25;
|
||||||
this.currentScaleText = document.getElementById('zoom-level');
|
this.currentScaleText = document.getElementById('zoom-level');
|
||||||
|
|
||||||
if (matchMedia('only screen and (max-width: 480px)').matches) {
|
if (matchMedia('only screen and (max-width: 480px)').matches) {
|
||||||
this.currentScale = 0.5;
|
this.currentScale = 1.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentScaleText.textContent = this.currentScale * 100 + '%';
|
this.currentScaleText.textContent = this.currentScale * 100 + '%';
|
||||||
|
@ -82,8 +82,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if($mobile)
|
@if($mobile)
|
||||||
<div class="flex justify-center">
|
<div class="w-full h-full overflow-auto mt-4">
|
||||||
<canvas id="pdf-placeholder" class="shadow rounded-lg bg-white mt-4 p-4"></canvas>
|
<canvas id="pdf-placeholder" class="shadow rounded-lg bg-white"></canvas>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<iframe id="pdf-iframe" src="{{ $url ?? $entity->pdf_file_path(null, 'url', true) }}" class="h-screen w-full border-0 mt-4"></iframe>
|
<iframe id="pdf-iframe" src="{{ $url ?? $entity->pdf_file_path(null, 'url', true) }}" class="h-screen w-full border-0 mt-4"></iframe>
|
||||||
|
@ -10,10 +10,12 @@
|
|||||||
*/
|
*/
|
||||||
namespace Tests\Feature;
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Models\Country;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
use Tests\MockAccountData;
|
use Tests\MockAccountData;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
@ -40,6 +42,77 @@ class ClientApiTest extends TestCase
|
|||||||
Model::reguard();
|
Model::reguard();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testClientCountryCodeValidationTrue()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'name' => $this->faker->firstName,
|
||||||
|
'id_number' => 'Coolio',
|
||||||
|
'country_code' => 'AM'
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = false;
|
||||||
|
|
||||||
|
try{
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->post('/api/v1/clients/', $data);
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||||
|
nlog($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testClientCountryCodeValidationTrueIso3()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'name' => $this->faker->firstName,
|
||||||
|
'id_number' => 'Coolio',
|
||||||
|
'country_code' => 'ARM'
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = false;
|
||||||
|
|
||||||
|
try{
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->post('/api/v1/clients/', $data);
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||||
|
nlog($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function testClientCountryCodeValidationFalse()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'name' => $this->faker->firstName,
|
||||||
|
'id_number' => 'Coolio',
|
||||||
|
'country_code' => 'AdfdfdfM'
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->post('/api/v1/clients/', $data);
|
||||||
|
|
||||||
|
$response->assertStatus(302);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public function testClientPost()
|
public function testClientPost()
|
||||||
{
|
{
|
||||||
$data = [
|
$data = [
|
||||||
@ -174,4 +247,45 @@ class ClientApiTest extends TestCase
|
|||||||
|
|
||||||
$this->assertTrue($arr['data'][0]['is_deleted']);
|
$this->assertTrue($arr['data'][0]['is_deleted']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testClientCurrencyCodeValidationTrue()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'name' => $this->faker->firstName,
|
||||||
|
'id_number' => 'Coolio',
|
||||||
|
'currency_code' => 'USD'
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->post('/api/v1/clients/', $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testClientCurrencyCodeValidationFalse()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'name' => $this->faker->firstName,
|
||||||
|
'id_number' => 'Coolio',
|
||||||
|
'currency_code' => 'R'
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->post('/api/v1/clients/', $data);
|
||||||
|
|
||||||
|
$response->assertStatus(302);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,25 +27,25 @@ class RefundUnitTest extends TestCase
|
|||||||
parent::setUp();
|
parent::setUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testProRataRefundMonthly()
|
// public function testProRataRefundMonthly()
|
||||||
{
|
// {
|
||||||
$pro_rata = new ProRata();
|
// $pro_rata = new ProRata();
|
||||||
$refund = $pro_rata->refund(10, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-31'), RecurringInvoice::FREQUENCY_MONTHLY);
|
// $refund = $pro_rata->refund(10, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-31'), RecurringInvoice::FREQUENCY_MONTHLY);
|
||||||
|
|
||||||
$this->assertEquals(9.68, $refund);
|
// $this->assertEquals(9.68, $refund);
|
||||||
|
|
||||||
$this->assertEquals(30, Carbon::parse('2021-01-01')->diffInDays(Carbon::parse('2021-01-31')));
|
// $this->assertEquals(30, Carbon::parse('2021-01-01')->diffInDays(Carbon::parse('2021-01-31')));
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
public function testProRataRefundYearly()
|
// public function testProRataRefundYearly()
|
||||||
{
|
// {
|
||||||
$pro_rata = new ProRata();
|
// $pro_rata = new ProRata();
|
||||||
|
|
||||||
$refund = $pro_rata->refund(10, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-31'), RecurringInvoice::FREQUENCY_ANNUALLY);
|
// $refund = $pro_rata->refund(10, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-31'), RecurringInvoice::FREQUENCY_ANNUALLY);
|
||||||
|
|
||||||
$this->assertEquals(0.82, $refund);
|
// $this->assertEquals(0.82, $refund);
|
||||||
}
|
// }
|
||||||
|
|
||||||
public function testDiffInDays()
|
public function testDiffInDays()
|
||||||
{
|
{
|
||||||
|
@ -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);
|
$refund = $pro_rata->refund($invoice->amount, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-06'), $subscription->frequency_id);
|
||||||
|
|
||||||
$this->assertEquals(1.61, $refund);
|
$this->assertEquals(1.67, $refund);
|
||||||
|
|
||||||
$pro_rata = new ProRata;
|
$pro_rata = new ProRata;
|
||||||
|
|
||||||
$upgrade = $pro_rata->charge($target->price, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-06'), $subscription->frequency_id);
|
$upgrade = $pro_rata->charge($target->price, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-06'), $subscription->frequency_id);
|
||||||
|
|
||||||
$this->assertEquals(3.23, $upgrade);
|
$this->assertEquals(3.33, $upgrade);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user