mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-12 14:12:44 +01:00
Throttle payment methods to prevent spam:
This commit is contained in:
parent
ffbfc11407
commit
f604e463c2
@ -33,6 +33,7 @@ class PaymentFactory
|
||||
$payment->transaction_reference = null;
|
||||
$payment->payer_id = null;
|
||||
$payment->status_id = Payment::STATUS_PENDING;
|
||||
$payment->exchange_rate = 1;
|
||||
|
||||
return $payment;
|
||||
}
|
||||
|
@ -30,6 +30,11 @@ class PaymentMethodController extends Controller
|
||||
{
|
||||
use MakesDates;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('throttle:10,1')->only('store');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
@ -92,7 +97,6 @@ class PaymentMethodController extends Controller
|
||||
|
||||
public function verify(ClientGatewayToken $payment_method)
|
||||
{
|
||||
// $gateway = $this->getClientGateway();
|
||||
|
||||
return $payment_method->gateway
|
||||
->driver(auth()->user()->client)
|
||||
|
@ -22,6 +22,7 @@ class BlackListRule implements Rule
|
||||
private array $blacklist = [
|
||||
'candassociates.com',
|
||||
'vusra.com',
|
||||
'fourthgenet.com',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -1450,6 +1450,20 @@ class CompanyImport implements ShouldQueue
|
||||
$new_obj->save(['timestamps' => false]);
|
||||
$new_obj->number = $this->getNextRecurringExpenseNumber($new_obj);
|
||||
}
|
||||
elseif($class == 'App\Models\Project' && is_null($obj->{$match_key})){
|
||||
$new_obj = new Project();
|
||||
$new_obj->company_id = $this->company->id;
|
||||
$new_obj->fill($obj_array);
|
||||
$new_obj->save(['timestamps' => false]);
|
||||
$new_obj->number = $this->getNextProjectNumber($new_obj);
|
||||
}
|
||||
elseif($class == 'App\Models\Task' && is_null($obj->{$match_key})){
|
||||
$new_obj = new Task();
|
||||
$new_obj->company_id = $this->company->id;
|
||||
$new_obj->fill($obj_array);
|
||||
$new_obj->save(['timestamps' => false]);
|
||||
$new_obj->number = $this->getNextTaskNumber($new_obj);
|
||||
}
|
||||
elseif($class == 'App\Models\CompanyLedger'){
|
||||
$new_obj = $class::firstOrNew(
|
||||
[$match_key => $obj->{$match_key}, 'company_id' => $this->company->id],
|
||||
|
89
app/Jobs/Report/ProfitAndLoss.php
Normal file
89
app/Jobs/Report/ProfitAndLoss.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Jobs\Report;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Company;
|
||||
use App\Services\Report\ProfitLoss;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ProfitAndLoss implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
protected Company $company;
|
||||
|
||||
protected array $payload;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param RecurringInvoice $recurring_invoice
|
||||
* @param string $db
|
||||
*/
|
||||
public function __construct(Company $company, array $payload)
|
||||
{
|
||||
$this->company = $company;
|
||||
|
||||
$this->payload = $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle() : void
|
||||
{
|
||||
|
||||
MultiDB::setDb($this->company->db);
|
||||
|
||||
/*
|
||||
payload variables.
|
||||
|
||||
start_date - Y-m-d
|
||||
end_date - Y-m-d
|
||||
date_range -
|
||||
all
|
||||
last7
|
||||
last30
|
||||
this_month
|
||||
last_month
|
||||
this_quarter
|
||||
last_quarter
|
||||
this_year
|
||||
custom
|
||||
income_billed - true = Invoiced || false = Payments
|
||||
expense_billed - true = Expensed || false = Expenses marked as paid
|
||||
include_tax - true tax_included || false - tax_excluded
|
||||
|
||||
*/
|
||||
|
||||
$pl = new ProfitLoss($this->company, $this->payload);
|
||||
|
||||
$pl->build();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public function failed($exception = null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -66,7 +66,11 @@ class PaymentRepository extends BaseRepository {
|
||||
|
||||
//check currencies here and fill the exchange rate data if necessary
|
||||
if (! $payment->id) {
|
||||
$this->processExchangeRates($data, $payment);
|
||||
$payment = $this->processExchangeRates($data, $payment);
|
||||
|
||||
/* This is needed here otherwise the ->fill() overwrites anything that exists*/
|
||||
if($payment->exchange_rate != 1)
|
||||
unset($data['exchange_rate']);
|
||||
|
||||
$is_existing_payment = false;
|
||||
$client = Client::where('id', $data['client_id'])->withTrashed()->first();
|
||||
@ -100,7 +104,12 @@ class PaymentRepository extends BaseRepository {
|
||||
$payment->status_id = Payment::STATUS_COMPLETED;
|
||||
|
||||
if (! $payment->currency_id && $client) {
|
||||
$payment->currency_id = $client->company->settings->currency_id;
|
||||
|
||||
if(property_exists($client->settings, 'currency_id'))
|
||||
$payment->currency_id = $client->settings->currency_id;
|
||||
else
|
||||
$payment->currency_id = $client->company->settings->currency_id;
|
||||
|
||||
}
|
||||
|
||||
$payment->save();
|
||||
@ -199,8 +208,9 @@ class PaymentRepository extends BaseRepository {
|
||||
public function processExchangeRates($data, $payment)
|
||||
{
|
||||
|
||||
if(array_key_exists('exchange_rate', $data) && isset($data['exchange_rate']))
|
||||
if(array_key_exists('exchange_rate', $data) && isset($data['exchange_rate']) && $data['exchange_rate'] != 1){
|
||||
return $payment;
|
||||
}
|
||||
|
||||
$client = Client::withTrashed()->find($data['client_id']);
|
||||
|
||||
@ -212,7 +222,6 @@ class PaymentRepository extends BaseRepository {
|
||||
$exchange_rate = new CurrencyApi();
|
||||
|
||||
$payment->exchange_rate = $exchange_rate->exchangeRate($client_currency, $company_currency, Carbon::parse($payment->date));
|
||||
// $payment->exchange_currency_id = $client_currency;
|
||||
$payment->exchange_currency_id = $company_currency;
|
||||
$payment->currency_id = $client_currency;
|
||||
|
||||
@ -221,7 +230,6 @@ class PaymentRepository extends BaseRepository {
|
||||
|
||||
$payment->currency_id = $company_currency;
|
||||
|
||||
|
||||
return $payment;
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ class MarkPaid extends AbstractService
|
||||
$payment->transaction_reference = ctrans('texts.manual_entry');
|
||||
$payment->currency_id = $this->invoice->client->getSetting('currency_id');
|
||||
$payment->is_manual = true;
|
||||
|
||||
|
||||
if($this->invoice->company->timezone())
|
||||
$payment->date = now()->addSeconds($this->invoice->company->timezone()->utc_offset)->format('Y-m-d');
|
||||
|
||||
@ -149,7 +149,7 @@ class MarkPaid extends AbstractService
|
||||
//$payment->exchange_currency_id = $client_currency; // 23/06/2021
|
||||
$payment->exchange_currency_id = $company_currency;
|
||||
|
||||
$payment->save();
|
||||
$payment->saveQuietly();
|
||||
|
||||
}
|
||||
|
||||
|
246
app/Services/Report/ProfitLoss.php
Normal file
246
app/Services/Report/ProfitLoss.php
Normal file
@ -0,0 +1,246 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Report;
|
||||
|
||||
use App\Models\Company;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class ProfitLoss
|
||||
{
|
||||
private bool $is_income_billed = true;
|
||||
|
||||
private bool $is_expense_billed = true;
|
||||
|
||||
private bool $is_tax_included = true;
|
||||
|
||||
private $start_date;
|
||||
|
||||
private $end_date;
|
||||
|
||||
/*
|
||||
payload variables.
|
||||
|
||||
start_date - Y-m-d
|
||||
end_date - Y-m-d
|
||||
date_range -
|
||||
all
|
||||
last7
|
||||
last30
|
||||
this_month
|
||||
last_month
|
||||
this_quarter
|
||||
last_quarter
|
||||
this_year
|
||||
custom
|
||||
income_billed - true = Invoiced || false = Payments
|
||||
expense_billed - true = Expensed || false = Expenses marked as paid
|
||||
include_tax - true tax_included || false - tax_excluded
|
||||
|
||||
*/
|
||||
|
||||
protected array $payload;
|
||||
|
||||
protected Company $company;
|
||||
|
||||
public function __construct(Company $company, array $payload)
|
||||
{
|
||||
|
||||
$this->company = $company;
|
||||
|
||||
$this->payload = $payload;
|
||||
|
||||
$this->setBillingReportType();
|
||||
}
|
||||
|
||||
public function build()
|
||||
{
|
||||
//get income
|
||||
|
||||
//sift foreign currencies - calculate both converted foreign amounts to native currency and also also group amounts by currency.
|
||||
|
||||
//get expenses
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
//returns an array of objects
|
||||
=> [
|
||||
{#2047
|
||||
+"amount": "706.480000",
|
||||
+"total_taxes": "35.950000",
|
||||
+"currency_id": ""1"",
|
||||
+"net_converted_amount": "670.5300000000",
|
||||
},
|
||||
{#2444
|
||||
+"amount": "200.000000",
|
||||
+"total_taxes": "0.000000",
|
||||
+"currency_id": ""23"",
|
||||
+"net_converted_amount": "1.7129479802",
|
||||
},
|
||||
{#2654
|
||||
+"amount": "140.000000",
|
||||
+"total_taxes": "40.000000",
|
||||
+"currency_id": ""12"",
|
||||
+"net_converted_amount": "69.3275024282",
|
||||
},
|
||||
]
|
||||
*/
|
||||
private function invoiceIncome()
|
||||
{
|
||||
return \DB::select( \DB::raw("
|
||||
SELECT
|
||||
sum(invoices.amount) as amount,
|
||||
sum(invoices.total_taxes) as total_taxes,
|
||||
sum(invoices.amount - invoices.total_taxes) as net_amount,
|
||||
IFNULL(JSON_EXTRACT( settings, '$.currency_id' ), :company_currency) AS currency_id,
|
||||
(sum(invoices.amount - invoices.total_taxes) / IFNULL(invoices.exchange_rate, 1)) AS net_converted_amount
|
||||
FROM clients
|
||||
JOIN invoices
|
||||
on invoices.client_id = clients.id
|
||||
WHERE invoices.status_id IN (2,3,4)
|
||||
AND invoices.company_id = :company_id
|
||||
AND invoices.amount > 0
|
||||
AND clients.is_deleted = 0
|
||||
AND invoices.is_deleted = 0
|
||||
AND (invoices.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
"), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date] );
|
||||
|
||||
|
||||
//
|
||||
// $total = array_reduce( commissionsArray, function ($sum, $entry) {
|
||||
// $sum += $entry->commission;
|
||||
// return $sum;
|
||||
// }, 0);
|
||||
}
|
||||
|
||||
private function paymentIncome()
|
||||
{
|
||||
return \DB::select( \DB::raw("
|
||||
SELECT
|
||||
SUM(coalesce(payments.amount - payments.refunded,0)) as payments,
|
||||
SUM(coalesce(payments.amount - payments.refunded,0)) * IFNULL(payments.exchange_rate ,1) as payments_converted
|
||||
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
|
||||
AND payments.company_id = :company_id
|
||||
AND (payments.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY payments.currency_id
|
||||
ORDER BY payments.currency_id;
|
||||
"), ['company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date]);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private function expenseCalc()
|
||||
{
|
||||
|
||||
return \DB::select( \DB::raw("
|
||||
SELECT sum(expenses.amount) as amount,
|
||||
IFNULL(expenses.currency_id, :company_currency) as currency_id
|
||||
FROM expenses
|
||||
WHERE expenses.is_deleted = 0
|
||||
AND expenses.company_id = :company_id
|
||||
AND (expenses.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
"), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date] );
|
||||
|
||||
}
|
||||
|
||||
private function setBillingReportType()
|
||||
{
|
||||
|
||||
if(array_key_exists('income_billed', $this->payload))
|
||||
$this->is_income_billed = boolval($this->payload['income_billed']);
|
||||
|
||||
if(array_key_exists('expense_billed', $this->payload))
|
||||
$this->is_expense_billed = boolval($this->payload['expense_billed']);
|
||||
|
||||
if(array_key_exists('include_tax', $this->payload))
|
||||
$this->is_tax_included = boolval($this->payload['is_tax_included']);
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
private function addDateRange($query)
|
||||
{
|
||||
|
||||
$date_range = $this->payload['date_range'];
|
||||
|
||||
try{
|
||||
|
||||
$custom_start_date = Carbon::parse($this->payload['start_date']);
|
||||
$custom_end_date = Carbon::parse($this->payload['end_date']);
|
||||
|
||||
}
|
||||
catch(\Exception $e){
|
||||
|
||||
$custom_start_date = now()->startOfYear();
|
||||
$custom_end_date = now();
|
||||
|
||||
}
|
||||
|
||||
switch ($date_range) {
|
||||
|
||||
case 'all':
|
||||
$this->start_date = now()->subYears(50);
|
||||
$this->end_date = now();
|
||||
// return $query;
|
||||
case 'last7':
|
||||
$this->start_date = now()->subDays(7);
|
||||
$this->end_date = now();
|
||||
// return $query->whereBetween($this->date_key, [now()->subDays(7), now()])->orderBy($this->date_key, 'ASC');
|
||||
case 'last30':
|
||||
$this->start_date = now()->subDays(30);
|
||||
$this->end_date = now();
|
||||
// return $query->whereBetween($this->date_key, [now()->subDays(30), now()])->orderBy($this->date_key, 'ASC');
|
||||
case 'this_month':
|
||||
$this->start_date = now()->startOfMonth();
|
||||
$this->end_date = now();
|
||||
//return $query->whereBetween($this->date_key, [now()->startOfMonth(), now()])->orderBy($this->date_key, 'ASC');
|
||||
case 'last_month':
|
||||
$this->start_date = now()->startOfMonth()->subMonth();
|
||||
$this->end_date = now()->startOfMonth()->subMonth()->endOfMonth();
|
||||
//return $query->whereBetween($this->date_key, [now()->startOfMonth()->subMonth(), now()->startOfMonth()->subMonth()->endOfMonth()])->orderBy($this->date_key, 'ASC');
|
||||
case 'this_quarter':
|
||||
$this->start_date = (new \Carbon\Carbon('-3 months'))->firstOfQuarter();
|
||||
$this->end_date = (new \Carbon\Carbon('-3 months'))->lastOfQuarter();
|
||||
//return $query->whereBetween($this->date_key, [(new \Carbon\Carbon('-3 months'))->firstOfQuarter(), (new \Carbon\Carbon('-3 months'))->lastOfQuarter()])->orderBy($this->date_key, 'ASC');
|
||||
case 'last_quarter':
|
||||
$this->start_date = (new \Carbon\Carbon('-6 months'))->firstOfQuarter();
|
||||
$this->end_date = (new \Carbon\Carbon('-6 months'))->lastOfQuarter();
|
||||
//return $query->whereBetween($this->date_key, [(new \Carbon\Carbon('-6 months'))->firstOfQuarter(), (new \Carbon\Carbon('-6 months'))->lastOfQuarter()])->orderBy($this->date_key, 'ASC');
|
||||
case 'this_year':
|
||||
$this->start_date = now()->startOfYear();
|
||||
$this->end_date = now();
|
||||
//return $query->whereBetween($this->date_key, [now()->startOfYear(), now()])->orderBy($this->date_key, 'ASC');
|
||||
case 'custom':
|
||||
$this->start_date = $custom_start_date;
|
||||
$this->end_date = $custom_end_date;
|
||||
//return $query->whereBetween($this->date_key, [$custom_start_date, $custom_end_date])->orderBy($this->date_key, 'ASC');
|
||||
default:
|
||||
$this->start_date = now()->startOfYear();
|
||||
$this->end_date = now();
|
||||
// return $query->whereBetween($this->date_key, [now()->startOfYear(), now()])->orderBy($this->date_key, 'ASC');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -8,7 +8,7 @@ Route::get('client/login', 'Auth\ContactLoginController@showLoginForm')->name('c
|
||||
Route::post('client/login', 'Auth\ContactLoginController@login')->name('client.login.submit');
|
||||
|
||||
Route::get('client/register/{company_key?}', 'Auth\ContactRegisterController@showRegisterForm')->name('client.register')->middleware(['domain_db', 'contact_account', 'contact_register','locale']);
|
||||
Route::post('client/register/{company_key?}', 'Auth\ContactRegisterController@register')->middleware(['domain_db', 'contact_account', 'contact_register', 'locale','throttle:10,1']);
|
||||
Route::post('client/register/{company_key?}', 'Auth\ContactRegisterController@register')->middleware(['domain_db', 'contact_account', 'contact_register', 'locale', 'throttle:10,1']);
|
||||
|
||||
Route::get('client/password/reset', 'Auth\ContactForgotPasswordController@showLinkRequestForm')->name('client.password.request')->middleware(['domain_db', 'contact_account','locale']);
|
||||
Route::post('client/password/email', 'Auth\ContactForgotPasswordController@sendResetLinkEmail')->name('client.password.email')->middleware('locale');
|
||||
@ -62,7 +62,7 @@ Route::group(['middleware' => ['auth:contact', 'locale', 'domain_db','check_clie
|
||||
Route::put('profile/{client_contact}/localization', 'ClientPortal\ProfileController@updateClientLocalization')->name('profile.edit_localization');
|
||||
|
||||
Route::get('payment_methods/{payment_method}/verification', 'ClientPortal\PaymentMethodController@verify')->name('payment_methods.verification');
|
||||
Route::post('payment_methods/{payment_method}/verification', 'ClientPortal\PaymentMethodController@processVerification');
|
||||
Route::post('payment_methods/{payment_method}/verification', 'ClientPortal\PaymentMethodController@processVerification')->middleware(['throttle:10,1']);
|
||||
|
||||
Route::get('payment_methods/confirm', 'ClientPortal\PaymentMethodController@store')->name('payment_methods.confirm');
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user