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]);
|
||||
}
|
||||
|
||||
$this->checkInvoiceBalances();
|
||||
// $this->checkInvoiceBalances();
|
||||
$this->checkInvoicePayments();
|
||||
$this->checkPaidToDates();
|
||||
// $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()
|
||||
{
|
||||
|
|
@ -496,8 +569,6 @@ class CheckData extends Command
|
|||
->pluck('p')
|
||||
->first();
|
||||
|
||||
// $total_paid = $total_amount - $total_refund;
|
||||
|
||||
$total_credit = $invoice->credits()->get()->sum('amount');
|
||||
|
||||
$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_paid_to_dates = 0;
|
||||
|
||||
foreach (Client::cursor()->where('is_deleted', 0)->where('clients.updated_at', '>', now()->subDays(2)) as $client) {
|
||||
//$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');
|
||||
$clients = $this->clientBalanceQuery();
|
||||
|
||||
/*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.*/
|
||||
if($client->balance != $invoice_balance)
|
||||
$invoice_balance -= $credit_balance;
|
||||
foreach($clients as $client)
|
||||
{
|
||||
$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->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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -213,12 +213,18 @@ abstract class QueryFilters
|
|||
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;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ class TokenController extends BaseController
|
|||
parent::__construct();
|
||||
|
||||
$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\Http\Requests\Request;
|
||||
use App\Http\ValidationRules\Client\CountryCodeExistsRule;
|
||||
use App\Http\ValidationRules\Ninja\CanStoreClientsRule;
|
||||
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
|
||||
use App\Models\Client;
|
||||
|
|
@ -51,6 +52,14 @@ class StoreClientRequest extends Request
|
|||
$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*/
|
||||
//$rules['name'] = 'required|min:1';
|
||||
$rules['settings'] = new ValidClientGroupSettingsRule();
|
||||
|
|
@ -133,6 +142,7 @@ class StoreClientRequest extends Request
|
|||
// 'unique' => ctrans('validation.unique', ['attribute' => ['email','number']),
|
||||
//'required' => trans('validation.required', ['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;
|
||||
})->first();
|
||||
|
||||
return (string) $currency->id;
|
||||
if($currency)
|
||||
return (string) $currency->id;
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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['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],
|
||||
$user_array,
|
||||
);
|
||||
)->restore();
|
||||
|
||||
$new_user->account_id = $this->account->id;
|
||||
$new_user->save(['timestamps' => false]);
|
||||
|
|
@ -1062,10 +1064,10 @@ class CompanyImport implements ShouldQueue
|
|||
unset($cu_array['company_id']);
|
||||
unset($cu_array['user_id']);
|
||||
|
||||
$new_cu = CompanyUser::firstOrNew(
|
||||
$new_cu = CompanyUser::withTrashed()->firstOrNew(
|
||||
['user_id' => $user_id, 'company_id' => $this->company->id],
|
||||
$cu_array,
|
||||
);
|
||||
)->restore();
|
||||
|
||||
$new_cu->account_id = $this->account->id;
|
||||
$new_cu->save(['timestamps' => false]);
|
||||
|
|
|
|||
|
|
@ -212,6 +212,8 @@ class NinjaMailerJob implements ShouldQueue
|
|||
|
||||
$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) {
|
||||
$this->logMailError('Gmail Token Invalid', $this->company->clients()->first());
|
||||
|
|
@ -225,9 +227,6 @@ class NinjaMailerJob implements ShouldQueue
|
|||
* just for this request.
|
||||
*/
|
||||
|
||||
// config(['mail.driver' => 'gmail']);
|
||||
// (new MailServiceProvider(app()))->register();
|
||||
|
||||
$token = $user->oauth_user_token->access_token;
|
||||
|
||||
$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) {
|
||||
if ($pm['gateway_type_id'] == GatewayType::DIRECT_DEBIT) {
|
||||
$cg = CompanyGateway::find($pm['company_gateway_id']);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class PaymentObserver
|
|||
->exists();
|
||||
|
||||
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();
|
||||
|
||||
if ($subscriptions) {
|
||||
WebhookHandler::dispatch(Webhook::EVENT_DELETE_PAYMENT, $payment, $payment->company, 'invoices');
|
||||
WebhookHandler::dispatch(Webhook::EVENT_DELETE_PAYMENT, $payment, $payment->company, 'invoices,client');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -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}
|
||||
|
|
@ -3,7 +3,7 @@ const MANIFEST = 'flutter-app-manifest';
|
|||
const TEMP = 'flutter-temp-cache';
|
||||
const CACHE_NAME = 'flutter-app-cache';
|
||||
const RESOURCES = {
|
||||
"version.json": "27abc97e9c76cf112b697fa080c304b5",
|
||||
"version.json": "3930722e1581f582eefe59c75ab50c99",
|
||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||
"assets/fonts/MaterialIcons-Regular.otf": "4e6447691c9509f7acdbf8a931a85ca1",
|
||||
|
|
@ -32,9 +32,9 @@ const RESOURCES = {
|
|||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "174c02fc4609e8fc4389f5d21f16a296",
|
||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||
"main.dart.js": "9331fefe016a4110385aae52ece5bb7c",
|
||||
"main.dart.js": "c2610220ba3a55e358c3c653d6242d0f",
|
||||
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
|
||||
"/": "3a8fb0769c1c1df7d1a95d627a2e2857"
|
||||
"/": "b8da32f39d55fc73f8a721a7e141bbc1"
|
||||
};
|
||||
|
||||
// The application shell files that are downloaded before a service worker can
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -13,7 +13,7 @@
|
|||
"/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/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/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",
|
||||
|
|
@ -36,7 +36,6 @@
|
|||
"/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-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=317a907834a0db9f8d41",
|
||||
"/css/app.css": "/css/app.css?id=6d7f6103a3a7738d363b",
|
||||
"/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"}
|
||||
|
|
@ -15,11 +15,11 @@ class PDF {
|
|||
this.context = canvas.getContext('2d');
|
||||
this.currentPage = 1;
|
||||
this.maxPages = 1;
|
||||
this.currentScale = 0.75;
|
||||
this.currentScale = 1.25;
|
||||
this.currentScaleText = document.getElementById('zoom-level');
|
||||
|
||||
if (matchMedia('only screen and (max-width: 480px)').matches) {
|
||||
this.currentScale = 0.5;
|
||||
this.currentScale = 1.25;
|
||||
}
|
||||
|
||||
this.currentScaleText.textContent = this.currentScale * 100 + '%';
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@
|
|||
</div>
|
||||
|
||||
@if($mobile)
|
||||
<div class="flex justify-center">
|
||||
<canvas id="pdf-placeholder" class="shadow rounded-lg bg-white mt-4 p-4"></canvas>
|
||||
<div class="w-full h-full overflow-auto mt-4">
|
||||
<canvas id="pdf-placeholder" class="shadow rounded-lg bg-white"></canvas>
|
||||
</div>
|
||||
@else
|
||||
<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;
|
||||
|
||||
use App\Models\Country;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
|
||||
|
|
@ -40,6 +42,77 @@ class ClientApiTest extends TestCase
|
|||
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()
|
||||
{
|
||||
$data = [
|
||||
|
|
@ -174,4 +247,45 @@ class ClientApiTest extends TestCase
|
|||
|
||||
$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();
|
||||
}
|
||||
|
||||
public function testProRataRefundMonthly()
|
||||
{
|
||||
$pro_rata = new ProRata();
|
||||
$refund = $pro_rata->refund(10, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-31'), RecurringInvoice::FREQUENCY_MONTHLY);
|
||||
// public function testProRataRefundMonthly()
|
||||
// {
|
||||
// $pro_rata = new ProRata();
|
||||
// $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()
|
||||
{
|
||||
$pro_rata = new ProRata();
|
||||
// public function testProRataRefundYearly()
|
||||
// {
|
||||
// $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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.61, $refund);
|
||||
$this->assertEquals(1.67, $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.23, $upgrade);
|
||||
$this->assertEquals(3.33, $upgrade);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue