mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
commit
3528b7689e
@ -1 +1 @@
|
|||||||
5.3.44
|
5.3.45
|
@ -112,7 +112,8 @@ class PaymentTermFilters extends QueryFilters
|
|||||||
*/
|
*/
|
||||||
public function entityFilter()
|
public function entityFilter()
|
||||||
{
|
{
|
||||||
|
return $this->builder->company();
|
||||||
//return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
//return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
||||||
return $this->builder->whereCompanyId(auth()->user()->company()->id)->orWhere('company_id', null);
|
// return $this->builder->whereCompanyId(auth()->user()->company()->id)->orWhere('company_id', null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,6 @@ class ProjectFilters extends QueryFilters
|
|||||||
$query = DB::table('projects')
|
$query = DB::table('projects')
|
||||||
->join('companies', 'companies.id', '=', 'projects.company_id')
|
->join('companies', 'companies.id', '=', 'projects.company_id')
|
||||||
->where('projects.company_id', '=', $company_id)
|
->where('projects.company_id', '=', $company_id)
|
||||||
//->whereRaw('(projects.name != "" or contacts.first_name != "" or contacts.last_name != "" or contacts.email != "")') // filter out buy now invoices
|
|
||||||
->select(
|
->select(
|
||||||
'projects.id',
|
'projects.id',
|
||||||
'projects.name',
|
'projects.name',
|
||||||
@ -140,6 +139,8 @@ class ProjectFilters extends QueryFilters
|
|||||||
public function entityFilter()
|
public function entityFilter()
|
||||||
{
|
{
|
||||||
//return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
//return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
||||||
return $this->builder->whereCompanyId(auth()->user()->company()->id)->orWhere('company_id', null);
|
// return $this->builder->whereCompanyId(auth()->user()->company()->id)->orWhere('company_id', null);
|
||||||
|
return $this->builder->company();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,8 @@ abstract class QueryFilters
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nlog('[Search] SQL: ' . $this->builder->toSql() . " Bindings: " . implode(', ', $this->builder->getBindings()));
|
||||||
|
|
||||||
return $this->builder->withTrashed();
|
return $this->builder->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class RecurringExpenseFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
$table = 'expenses';
|
$table = 'recurring_expenses';
|
||||||
$filters = explode(',', $filter);
|
$filters = explode(',', $filter);
|
||||||
|
|
||||||
return $this->builder->where(function ($query) use ($filters, $table) {
|
return $this->builder->where(function ($query) use ($filters, $table) {
|
||||||
|
@ -53,7 +53,7 @@ class RecurringInvoiceFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
$table = 'recurring_';
|
$table = 'recurring_invoices';
|
||||||
$filters = explode(',', $filter);
|
$filters = explode(',', $filter);
|
||||||
|
|
||||||
return $this->builder->where(function ($query) use ($filters, $table) {
|
return $this->builder->where(function ($query) use ($filters, $table) {
|
||||||
|
@ -22,6 +22,7 @@ use App\Utils\Traits\AppSetup;
|
|||||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use League\Fractal\Manager;
|
use League\Fractal\Manager;
|
||||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||||
use League\Fractal\Resource\Collection;
|
use League\Fractal\Resource\Collection;
|
||||||
@ -619,7 +620,9 @@ class BaseController extends Controller
|
|||||||
|
|
||||||
$query->with($includes);
|
$query->with($includes);
|
||||||
|
|
||||||
if (auth()->user() && ! auth()->user()->hasPermission('view_'.lcfirst(class_basename($this->entity_type)))) {
|
// 10-01-2022 need to ensure we snake case properly here to ensure permissions work as expected
|
||||||
|
// if (auth()->user() && ! auth()->user()->hasPermission('view_'.lcfirst(class_basename($this->entity_type)))) {
|
||||||
|
if (auth()->user() && ! auth()->user()->hasPermission('view'.lcfirst(class_basename(Str::snake($this->entity_type))))) {
|
||||||
$query->where('user_id', '=', auth()->user()->id);
|
$query->where('user_id', '=', auth()->user()->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +401,7 @@ class InvoiceController extends BaseController
|
|||||||
|
|
||||||
$invoice = $this->invoice_repo->save($request->all(), $invoice);
|
$invoice = $this->invoice_repo->save($request->all(), $invoice);
|
||||||
|
|
||||||
$invoice->service()->triggeredActions($request)->deletePdf();
|
$invoice->service()->triggeredActions($request)->touchPdf();
|
||||||
|
|
||||||
event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||||
|
|
||||||
@ -708,7 +708,7 @@ class InvoiceController extends BaseController
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'cancel':
|
case 'cancel':
|
||||||
$invoice = $invoice->service()->handleCancellation()->deletePdf()->save();
|
$invoice = $invoice->service()->handleCancellation()->deletePdf()->touchPdf()->save();
|
||||||
|
|
||||||
if (! $bulk) {
|
if (! $bulk) {
|
||||||
$this->itemResponse($invoice);
|
$this->itemResponse($invoice);
|
||||||
|
@ -23,6 +23,43 @@ use Illuminate\Http\Response;
|
|||||||
class StaticController extends BaseController
|
class StaticController extends BaseController
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the list of Invoices.
|
||||||
|
*
|
||||||
|
* @param InvoiceFilters $filters The filters
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
* @OA\Get(
|
||||||
|
* path="/api/v1/statics",
|
||||||
|
* operationId="getStatics",
|
||||||
|
* tags={"statics"},
|
||||||
|
* summary="Gets a list of statics",
|
||||||
|
* description="Lists all statics",
|
||||||
|
*
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A list of static data",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
public function __invoke()
|
public function __invoke()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ class RequiredClientInfo extends Component
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Str::startsWith($field['name'], 'contact_')) {
|
if (Str::startsWith($field['name'], 'contact_')) {
|
||||||
if (empty($this->contact->client->{$_field}) || is_null($this->contact->client->{$_field})) {
|
if (empty($this->contact->{$_field}) || is_null($this->contact->{$_field})) {
|
||||||
// if ((empty($this->contact->{$_field}) || is_null($this->contact->{$_field})) || $this->contact->client->{$_field} == 840) {
|
// if ((empty($this->contact->{$_field}) || is_null($this->contact->{$_field})) || $this->contact->client->{$_field} == 840) {
|
||||||
$this->show_form = true;
|
$this->show_form = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -54,7 +54,10 @@ class StorePaymentRequest extends Request
|
|||||||
if (isset($input['invoices']) && is_array($input['invoices']) !== false) {
|
if (isset($input['invoices']) && is_array($input['invoices']) !== false) {
|
||||||
foreach ($input['invoices'] as $key => $value) {
|
foreach ($input['invoices'] as $key => $value) {
|
||||||
$input['invoices'][$key]['invoice_id'] = $this->decodePrimaryKey($value['invoice_id']);
|
$input['invoices'][$key]['invoice_id'] = $this->decodePrimaryKey($value['invoice_id']);
|
||||||
$invoices_total += $value['amount'];
|
|
||||||
|
if(array_key_exists('amount', $value))
|
||||||
|
$invoices_total += $value['amount'];
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,12 +94,12 @@ class StorePaymentRequest extends Request
|
|||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
$rules = [
|
$rules = [
|
||||||
'amount' => 'numeric|required',
|
'amount' => 'sometimes|numeric',
|
||||||
'amount' => [new PaymentAmountsBalanceRule(), new ValidCreditsPresentRule()],
|
'amount' => [new PaymentAmountsBalanceRule(), new ValidCreditsPresentRule()],
|
||||||
'client_id' => 'bail|required|exists:clients,id',
|
'client_id' => 'bail|required|exists:clients,id',
|
||||||
'invoices.*.invoice_id' => 'bail|required|distinct|exists:invoices,id',
|
'invoices.*.invoice_id' => 'bail|required|distinct|exists:invoices,id',
|
||||||
|
'invoices.*.amount' => 'bail|required',
|
||||||
'invoices.*.invoice_id' => new ValidInvoicesRules($this->all()),
|
'invoices.*.invoice_id' => new ValidInvoicesRules($this->all()),
|
||||||
'invoices.*.amount' => 'required',
|
|
||||||
'credits.*.credit_id' => 'bail|required|exists:credits,id',
|
'credits.*.credit_id' => 'bail|required|exists:credits,id',
|
||||||
'credits.*.credit_id' => new ValidCreditsRules($this->all()),
|
'credits.*.credit_id' => new ValidCreditsRules($this->all()),
|
||||||
'credits.*.amount' => ['required', new CreditsSumRule($this->all())],
|
'credits.*.amount' => ['required', new CreditsSumRule($this->all())],
|
||||||
|
@ -58,7 +58,7 @@ class StoreUserRequest extends Request
|
|||||||
{
|
{
|
||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
//unique user rule - check company_user table for user_id / company_id / account_id if none exist we can add the user. ELSE return false
|
//unique user rule - check company_user table for user_id / company_id / account_id if none exist we can add the user. ELSE return false
|
||||||
|
|
||||||
if(array_key_exists('email', $input))
|
if(array_key_exists('email', $input))
|
||||||
$input['email'] = trim($input['email']);
|
$input['email'] = trim($input['email']);
|
||||||
|
@ -33,13 +33,18 @@ class CanAddUserRule implements Rule
|
|||||||
public function passes($attribute, $value)
|
public function passes($attribute, $value)
|
||||||
{
|
{
|
||||||
|
|
||||||
$count = CompanyUser::query()
|
/* If the user is active then we can add them to the company */
|
||||||
->where('company_user.account_id', auth()->user()->account_id)
|
if(User::where('email', request()->input('email'))->where('account_id', auth()->user()->account_id)->where('is_deleted',0)->exists())
|
||||||
->join('users', 'users.id', '=', 'company_user.user_id')
|
return true;
|
||||||
->whereNull('users.deleted_at')
|
|
||||||
->whereNull('company_user.deleted_at')
|
/* Check that we have sufficient quota to allow this to happen */
|
||||||
->distinct()
|
$count = CompanyUser::query()
|
||||||
->count('company_user.user_id');
|
->where('company_user.account_id', auth()->user()->account_id)
|
||||||
|
->join('users', 'users.id', '=', 'company_user.user_id')
|
||||||
|
->whereNull('users.deleted_at')
|
||||||
|
->whereNull('company_user.deleted_at')
|
||||||
|
->distinct()
|
||||||
|
->count('company_user.user_id');
|
||||||
|
|
||||||
return $count < auth()->user()->company()->account->num_users;
|
return $count < auth()->user()->company()->account->num_users;
|
||||||
|
|
||||||
|
@ -57,6 +57,11 @@ class ValidInvoicesRules implements Rule
|
|||||||
|
|
||||||
$unique_array[] = $invoice['invoice_id'];
|
$unique_array[] = $invoice['invoice_id'];
|
||||||
|
|
||||||
|
if(!array_key_exists('amount', $invoice)){
|
||||||
|
$this->error_msg = ctrans('texts.amount') . " required";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$inv = Invoice::whereId($invoice['invoice_id'])->first();
|
$inv = Invoice::whereId($invoice['invoice_id'])->first();
|
||||||
|
|
||||||
if (! $inv) {
|
if (! $inv) {
|
||||||
|
@ -79,6 +79,11 @@ class ValidRefundableRequest implements Rule
|
|||||||
{
|
{
|
||||||
$invoice = Invoice::whereId($invoice['invoice_id'])->whereCompanyId($payment->company_id)->withTrashed()->first();
|
$invoice = Invoice::whereId($invoice['invoice_id'])->whereCompanyId($payment->company_id)->withTrashed()->first();
|
||||||
|
|
||||||
|
if(!$invoice){
|
||||||
|
$this->error_msg = "Invoice not found for refund";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if ($payment->invoices()->exists()) {
|
if ($payment->invoices()->exists()) {
|
||||||
$paymentable_invoice = $payment->invoices->where('id', $invoice->id)->first();
|
$paymentable_invoice = $payment->invoices->where('id', $invoice->id)->first();
|
||||||
|
|
||||||
|
@ -59,19 +59,30 @@ class PaymentAmountsBalanceRule implements Rule
|
|||||||
|
|
||||||
if (request()->input('credits') && is_array(request()->input('credits'))) {
|
if (request()->input('credits') && is_array(request()->input('credits'))) {
|
||||||
foreach (request()->input('credits') as $credit) {
|
foreach (request()->input('credits') as $credit) {
|
||||||
$payment_amounts += $credit['amount'];
|
|
||||||
|
if(array_key_exists('amount', $credit))
|
||||||
|
$payment_amounts += $credit['amount'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request()->input('invoices') && is_array(request()->input('invoices'))) {
|
if (request()->input('invoices') && is_array(request()->input('invoices'))) {
|
||||||
foreach (request()->input('invoices') as $invoice) {
|
foreach (request()->input('invoices') as $invoice) {
|
||||||
$invoice_amounts += $invoice['amount'];
|
|
||||||
|
if(array_key_exists('amount', $invoice))
|
||||||
|
$invoice_amounts += $invoice['amount'];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nlog(request()->input('invoices'));
|
||||||
|
// nlog($payment_amounts);
|
||||||
|
// nlog($invoice_amounts);
|
||||||
|
|
||||||
|
nlog($payment_amounts ." >= " . $invoice_amounts);
|
||||||
|
|
||||||
|
return $payment_amounts >= $invoice_amounts;
|
||||||
|
|
||||||
return $payment_amounts >= $invoice_amounts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ class SendRecurring implements ShouldQueue
|
|||||||
$invoice = $this->createRecurringInvitations($invoice);
|
$invoice = $this->createRecurringInvitations($invoice);
|
||||||
|
|
||||||
/* 09-01-2022 ensure we create the PDFs at this point in time! */
|
/* 09-01-2022 ensure we create the PDFs at this point in time! */
|
||||||
$invoice->service()->touchPdf();
|
$invoice->service()->touchPdf(true);
|
||||||
|
|
||||||
nlog("updating recurring invoice dates");
|
nlog("updating recurring invoice dates");
|
||||||
/* Set next date here to prevent a recurring loop forming */
|
/* Set next date here to prevent a recurring loop forming */
|
||||||
|
@ -1866,10 +1866,19 @@ class Import implements ShouldQueue
|
|||||||
|
|
||||||
private function processNinjaTokens(array $data)
|
private function processNinjaTokens(array $data)
|
||||||
{
|
{
|
||||||
|
|
||||||
nlog("attempting to process Ninja Tokens");
|
nlog("attempting to process Ninja Tokens");
|
||||||
|
|
||||||
if(Ninja::isHosted())
|
if(Ninja::isHosted()){
|
||||||
\Modules\Admin\Jobs\Account\NinjaUser::dispatchNow($data, $this->company);
|
|
||||||
|
try{
|
||||||
|
\Modules\Admin\Jobs\Account\NinjaUser::dispatchNow($data, $this->company);
|
||||||
|
}
|
||||||
|
catch(\Exception $e){
|
||||||
|
nlog($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +80,8 @@ class ReminderJob implements ShouldQueue
|
|||||||
$invoice->service()->touchReminder($reminder_template)->save();
|
$invoice->service()->touchReminder($reminder_template)->save();
|
||||||
$invoice = $this->calcLateFee($invoice, $reminder_template);
|
$invoice = $this->calcLateFee($invoice, $reminder_template);
|
||||||
|
|
||||||
|
$invoice->service()->touchPdf();
|
||||||
|
|
||||||
//check if this reminder needs to be emailed
|
//check if this reminder needs to be emailed
|
||||||
if(in_array($reminder_template, ['reminder1','reminder2','reminder3','reminder_endless']) && $invoice->client->getSetting("enable_".$reminder_template))
|
if(in_array($reminder_template, ['reminder1','reminder2','reminder3','reminder_endless']) && $invoice->client->getSetting("enable_".$reminder_template))
|
||||||
{
|
{
|
||||||
|
@ -43,7 +43,7 @@ class InvoiceArchivedActivity implements ShouldQueue
|
|||||||
{
|
{
|
||||||
MultiDB::setDb($event->company->db);
|
MultiDB::setDb($event->company->db);
|
||||||
|
|
||||||
$event->invoice->service()->deletePdf();
|
// $event->invoice->service()->deletePdf();
|
||||||
|
|
||||||
$fields = new stdClass;
|
$fields = new stdClass;
|
||||||
|
|
||||||
|
@ -195,7 +195,10 @@ class BaseModel extends Model
|
|||||||
// Remove any runs of periods (thanks falstro!)
|
// Remove any runs of periods (thanks falstro!)
|
||||||
$formatted_number = mb_ereg_replace("([\.]{2,})", '', $formatted_number);
|
$formatted_number = mb_ereg_replace("([\.]{2,})", '', $formatted_number);
|
||||||
|
|
||||||
$formatted_number = str_replace(" ", "_", $formatted_number);
|
// $formatted_number = str_replace(" ", "_", $formatted_number);
|
||||||
|
|
||||||
|
//11-01-2021 fixes for multiple spaces
|
||||||
|
$formatted_number = preg_replace('/\s+/', '_', $formatted_number);
|
||||||
|
|
||||||
return $formatted_number;
|
return $formatted_number;
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ class Company extends BaseModel
|
|||||||
|
|
||||||
public function users()
|
public function users()
|
||||||
{
|
{
|
||||||
return $this->hasManyThrough(User::class, CompanyUser::class, 'company_id', 'id', 'id', 'user_id');
|
return $this->hasManyThrough(User::class, CompanyUser::class, 'company_id', 'id', 'id', 'user_id')->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function expense_categories()
|
public function expense_categories()
|
||||||
|
@ -442,7 +442,7 @@ class BaseDriver extends AbstractPaymentDriver
|
|||||||
|
|
||||||
$invoices->each(function ($invoice) {
|
$invoices->each(function ($invoice) {
|
||||||
|
|
||||||
$invoice->service()->deletePdf();
|
$invoice->service()->touchPdf();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -494,7 +494,7 @@ class BaseDriver extends AbstractPaymentDriver
|
|||||||
|
|
||||||
$invoices->each(function ($invoice){
|
$invoices->each(function ($invoice){
|
||||||
|
|
||||||
$invoice->service()->deletePdf();
|
$invoice->service()->touchPdf();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -234,6 +234,15 @@ class GoCardlessPaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
$this->init();
|
$this->init();
|
||||||
|
|
||||||
|
|
||||||
|
if(!is_array($request->events) || !is_object($request->events)){
|
||||||
|
|
||||||
|
nlog("No GoCardless events to process in response?");
|
||||||
|
return response()->json([], 200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach ($request->events as $event) {
|
foreach ($request->events as $event) {
|
||||||
if ($event['action'] === 'confirmed') {
|
if ($event['action'] === 'confirmed') {
|
||||||
$payment = Payment::query()
|
$payment = Payment::query()
|
||||||
|
@ -321,7 +321,7 @@ class MolliePaymentDriver extends BaseDriver
|
|||||||
// we may not have a payment record - in these cases we need to re-construct the payment
|
// we may not have a payment record - in these cases we need to re-construct the payment
|
||||||
// record from the meta data in the payment hash.
|
// record from the meta data in the payment hash.
|
||||||
|
|
||||||
if($payment && property_exists($payment->metadata, 'payment_hash') && $payment->metadata->payment_hash){
|
if($payment && property_exists($payment->metadata, 'hash') && $payment->metadata->hash){
|
||||||
|
|
||||||
/* Harvest Payment Hash*/
|
/* Harvest Payment Hash*/
|
||||||
$payment_hash = PaymentHash::where('hash', $payment->metadata->hash)->first();
|
$payment_hash = PaymentHash::where('hash', $payment->metadata->hash)->first();
|
||||||
|
@ -194,13 +194,18 @@ class BrowserPay implements MethodInterface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$domain = config('ninja.app_url');
|
// $domain = config('ninja.app_url');
|
||||||
|
|
||||||
if (Ninja::isHosted()) {
|
// if (Ninja::isHosted()) {
|
||||||
$domain = isset($this->stripe->company_gateway->company->portal_domain)
|
// $domain = isset($this->stripe->company_gateway->company->portal_domain)
|
||||||
? $this->stripe->company_gateway->company->portal_domain
|
// ? $this->stripe->company_gateway->company->portal_domain
|
||||||
: $this->stripe->company_gateway->company->domain();
|
// : $this->stripe->company_gateway->company->domain();
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
$domain = $this->getAppleDomain();
|
||||||
|
|
||||||
|
if(!$domain)
|
||||||
|
throw new PaymentFailed('Unable to register Domain with Apple Pay', 500);
|
||||||
|
|
||||||
$response = ApplePayDomain::create([
|
$response = ApplePayDomain::create([
|
||||||
'domain_name' => $domain,
|
'domain_name' => $domain,
|
||||||
@ -212,4 +217,36 @@ class BrowserPay implements MethodInterface
|
|||||||
|
|
||||||
$this->stripe->company_gateway->save();
|
$this->stripe->company_gateway->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function getAppleDomain()
|
||||||
|
{
|
||||||
|
|
||||||
|
$domain = '';
|
||||||
|
|
||||||
|
if(Ninja::isHosted())
|
||||||
|
{
|
||||||
|
|
||||||
|
if($this->company_gateway->company->portal_mode == 'domain'){
|
||||||
|
$domain = $this->company_gateway->company->portal_domain;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$domain = $this->company_gateway->company->subdomain . '.' . config('ninja.app_domain');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
$domain = config('ninja.app_url');
|
||||||
|
}
|
||||||
|
|
||||||
|
$parsed_url = parse_url($domain);
|
||||||
|
|
||||||
|
if(array_key_exists('host', $parsed_url))
|
||||||
|
return $parsed_url['host'];
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -189,6 +189,14 @@ class UserRepository extends BaseRepository
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Ninja::isHosted()) {
|
||||||
|
|
||||||
|
$count = User::where('account_id', auth()->user()->account_id)->count();
|
||||||
|
if($count >= auth()->user()->account->num_users)
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
$user->is_deleted = false;
|
$user->is_deleted = false;
|
||||||
$user->save();
|
$user->save();
|
||||||
$user->restore();
|
$user->restore();
|
||||||
|
@ -236,7 +236,7 @@ class Statement
|
|||||||
private function invoiceStatuses() :array
|
private function invoiceStatuses() :array
|
||||||
{
|
{
|
||||||
$status = 'all';
|
$status = 'all';
|
||||||
nlog($this->options);
|
|
||||||
if(array_key_exists('status', $this->options))
|
if(array_key_exists('status', $this->options))
|
||||||
$status = $this->options['status'];
|
$status = $this->options['status'];
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ class AutoBillInvoice extends AbstractService
|
|||||||
}
|
}
|
||||||
catch(\Exception $e){
|
catch(\Exception $e){
|
||||||
nlog("payment NOT captured for ". $this->invoice->number . " with error " . $e->getMessage());
|
nlog("payment NOT captured for ". $this->invoice->number . " with error " . $e->getMessage());
|
||||||
// nlog($e->getMessage());
|
$this->invoice->service()->removeUnpaidGatewayFees()->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
if($payment){
|
if($payment){
|
||||||
|
@ -390,18 +390,27 @@ class InvoiceService
|
|||||||
*/
|
*/
|
||||||
public function touchPdf($force = false)
|
public function touchPdf($force = false)
|
||||||
{
|
{
|
||||||
if($force){
|
try {
|
||||||
|
|
||||||
|
if($force){
|
||||||
|
|
||||||
|
$this->invoice->invitations->each(function ($invitation) {
|
||||||
|
CreateEntityPdf::dispatchNow($invitation);
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
$this->invoice->invitations->each(function ($invitation) {
|
$this->invoice->invitations->each(function ($invitation) {
|
||||||
CreateEntityPdf::dispatchNow($invitation);
|
CreateEntityPdf::dispatch($invitation);
|
||||||
});
|
});
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
}
|
||||||
|
catch(\Exception $e){
|
||||||
|
|
||||||
$this->invoice->invitations->each(function ($invitation) {
|
nlog("failed creating invoices in Touch PDF");
|
||||||
CreateEntityPdf::dispatch($invitation);
|
|
||||||
});
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,8 @@ class MarkPaid extends AbstractService
|
|||||||
$this->invoice
|
$this->invoice
|
||||||
->service()
|
->service()
|
||||||
->applyNumber()
|
->applyNumber()
|
||||||
->deletePdf()
|
// ->deletePdf()
|
||||||
|
->touchPdf()
|
||||||
->save();
|
->save();
|
||||||
|
|
||||||
$payment->ledger()
|
$payment->ledger()
|
||||||
|
@ -37,6 +37,8 @@ class SendEmail
|
|||||||
$this->payment->client->contacts->each(function ($contact) {
|
$this->payment->client->contacts->each(function ($contact) {
|
||||||
if ($contact->email) {
|
if ($contact->email) {
|
||||||
EmailPayment::dispatchNow($this->payment, $this->payment->company, $contact);
|
EmailPayment::dispatchNow($this->payment, $this->payment->company, $contact);
|
||||||
|
return false;
|
||||||
|
//11-01-2021 only send payment receipt to the first contact
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ class UpdateInvoicePayment
|
|||||||
$invoice->refresh();
|
$invoice->refresh();
|
||||||
|
|
||||||
$invoice->service()
|
$invoice->service()
|
||||||
->deletePdf()
|
->touchPdf(true)
|
||||||
->workFlow()
|
->workFlow()
|
||||||
->save();
|
->save();
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ trait ClientGroupSettingsSaver
|
|||||||
case 'double':
|
case 'double':
|
||||||
return is_float($value) || is_numeric(strval($value));
|
return is_float($value) || is_numeric(strval($value));
|
||||||
case 'string':
|
case 'string':
|
||||||
return method_exists($value, '__toString') || is_null($value) || is_string($value);
|
return ( is_string( $value ) && method_exists($value, '__toString') ) || is_null($value) || is_string($value);
|
||||||
case 'bool':
|
case 'bool':
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
return is_bool($value) || (int) filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
return is_bool($value) || (int) filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
||||||
|
@ -61,7 +61,7 @@ trait CompanyGatewayFeesAndLimitsSaver
|
|||||||
case 'double':
|
case 'double':
|
||||||
return is_float($value) || is_numeric(strval($value));
|
return is_float($value) || is_numeric(strval($value));
|
||||||
case 'string':
|
case 'string':
|
||||||
return method_exists($value, '__toString') || is_null($value) || is_string($value);
|
return ( is_string( $value ) && method_exists($value, '__toString') ) || is_null($value) || is_string($value);
|
||||||
case 'bool':
|
case 'bool':
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
return is_bool($value) || (int) filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
return is_bool($value) || (int) filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
||||||
|
@ -232,7 +232,6 @@ trait CompanySettingsSaver
|
|||||||
return is_float($value) || is_numeric(strval($value));
|
return is_float($value) || is_numeric(strval($value));
|
||||||
case 'string':
|
case 'string':
|
||||||
return (is_string($value) && method_exists($value, '__toString')) || is_null($value) || is_string($value);
|
return (is_string($value) && method_exists($value, '__toString')) || is_null($value) || is_string($value);
|
||||||
//return is_null($value) || is_string($value);
|
|
||||||
case 'bool':
|
case 'bool':
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
return is_bool($value) || (int) filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
return is_bool($value) || (int) filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
||||||
|
@ -99,6 +99,9 @@ trait MakesDates
|
|||||||
|
|
||||||
public function translateDate($date, $format, $locale)
|
public function translateDate($date, $format, $locale)
|
||||||
{
|
{
|
||||||
|
if(empty($date))
|
||||||
|
return '';
|
||||||
|
|
||||||
Carbon::setLocale($locale);
|
Carbon::setLocale($locale);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -94,7 +94,7 @@ trait SettingsSaver
|
|||||||
case 'double':
|
case 'double':
|
||||||
return is_float($value) || is_numeric(strval($value));
|
return is_float($value) || is_numeric(strval($value));
|
||||||
case 'string':
|
case 'string':
|
||||||
return method_exists($value, '__toString') || is_null($value) || is_string($value);
|
return !is_int($value) || ( is_string( $value ) && method_exists($value, '__toString') ) || is_null($value) || is_string($value);
|
||||||
case 'bool':
|
case 'bool':
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
return is_bool($value) || (int) filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
return is_bool($value) || (int) filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
||||||
|
@ -14,8 +14,8 @@ return [
|
|||||||
'require_https' => env('REQUIRE_HTTPS', true),
|
'require_https' => env('REQUIRE_HTTPS', true),
|
||||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||||
'app_version' => '5.3.44',
|
'app_version' => '5.3.45',
|
||||||
'app_tag' => '5.3.44',
|
'app_tag' => '5.3.45',
|
||||||
'minimum_client_version' => '5.0.16',
|
'minimum_client_version' => '5.0.16',
|
||||||
'terms_version' => '1.0.1',
|
'terms_version' => '1.0.1',
|
||||||
'api_secret' => env('API_SECRET', ''),
|
'api_secret' => env('API_SECRET', ''),
|
||||||
|
@ -38,7 +38,10 @@
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#entity-details p { margin-right: 20px; }
|
#entity-details p {
|
||||||
|
margin-right: 20px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.header-wrapper #entity-details {
|
.header-wrapper #entity-details {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
167
tests/Feature/Payments/StorePaymentValidationTest.php
Normal file
167
tests/Feature/Payments/StorePaymentValidationTest.php
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
namespace Tests\Feature\Payments;
|
||||||
|
|
||||||
|
use App\DataMapper\ClientSettings;
|
||||||
|
use App\Factory\ClientFactory;
|
||||||
|
use App\Factory\CreditFactory;
|
||||||
|
use App\Factory\InvoiceFactory;
|
||||||
|
use App\Factory\InvoiceItemFactory;
|
||||||
|
use App\Factory\PaymentFactory;
|
||||||
|
use App\Helpers\Invoice\InvoiceSum;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\ClientContact;
|
||||||
|
use App\Models\Credit;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
use Illuminate\Foundation\Testing\WithoutEvents;
|
||||||
|
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Tests\MockAccountData;
|
||||||
|
use Tests\MockUnitData;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
class StorePaymentValidationTest extends TestCase
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
use DatabaseTransactions;
|
||||||
|
use MockAccountData;
|
||||||
|
use WithoutEvents;
|
||||||
|
|
||||||
|
public function setUp() :void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
Session::start();
|
||||||
|
|
||||||
|
$this->faker = \Faker\Factory::create();
|
||||||
|
|
||||||
|
Model::reguard();
|
||||||
|
|
||||||
|
$this->makeTestData();
|
||||||
|
|
||||||
|
|
||||||
|
$this->withoutMiddleware(
|
||||||
|
ThrottleRequests::class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testValidPayment()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'amount' => 0,
|
||||||
|
'client_id' => $this->client->hashed_id,
|
||||||
|
'invoices' => [
|
||||||
|
],
|
||||||
|
'date' => '2019/12/12',
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->post('/api/v1/payments/', $data);
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||||
|
nlog($e->validator->getMessageBag());
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testValidPaymentWithAmount()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'amount' => 0,
|
||||||
|
'client_id' => $this->client->hashed_id,
|
||||||
|
'invoices' => [
|
||||||
|
[
|
||||||
|
'invoice_id' => $this->invoice->hashed_id,
|
||||||
|
'amount' => 10,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'credits' => [
|
||||||
|
[
|
||||||
|
'credit_id' => $this->credit->hashed_id,
|
||||||
|
'amount' => 5
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'date' => '2019/12/12',
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->post('/api/v1/payments/', $data);
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||||
|
nlog($e->validator->getMessageBag());
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidPaymentWithInvalidData()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'amount' => 0,
|
||||||
|
'client_id' => $this->client->hashed_id,
|
||||||
|
'invoices' => [
|
||||||
|
[
|
||||||
|
'invoice_id' => $this->invoice->hashed_id,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'credits' => [
|
||||||
|
[
|
||||||
|
'credit_id' => $this->credit->hashed_id,
|
||||||
|
'amount' => 5
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'date' => '2019/12/12',
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = false;
|
||||||
|
|
||||||
|
try{
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->post('/api/v1/payments/', $data);
|
||||||
|
}catch(ValidationException $e){
|
||||||
|
$response->assertStatus(302);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -84,10 +84,35 @@ class ProjectApiTest extends TestCase
|
|||||||
$response->assertStatus(302);
|
$response->assertStatus(302);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProjectPostFilters()
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'name' => "Sherlock",
|
||||||
|
'client_id' => $this->client->hashed_id,
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->post('/api/v1/projects', $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->get('/api/v1/projects?filter=Sherlock');
|
||||||
|
|
||||||
|
$arr = $response->json();
|
||||||
|
|
||||||
|
$this->assertEquals(1, count($arr['data']));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testProjectPut()
|
public function testProjectPut()
|
||||||
{
|
{
|
||||||
$data = [
|
$data = [
|
||||||
|
@ -84,7 +84,7 @@ class CompanyLedgerTest extends TestCase
|
|||||||
|
|
||||||
$settings = CompanySettings::defaults();
|
$settings = CompanySettings::defaults();
|
||||||
|
|
||||||
$settings->company_logo = 'https://app.invoiceninja.com/favicon-v2.png';
|
$settings->company_logo = 'https://pdf.invoicing.co/favicon-v2.png';
|
||||||
$settings->website = 'www.invoiceninja.com';
|
$settings->website = 'www.invoiceninja.com';
|
||||||
$settings->address1 = 'Address 1';
|
$settings->address1 = 'Address 1';
|
||||||
$settings->address2 = 'Address 2';
|
$settings->address2 = 'Address 2';
|
||||||
|
@ -192,7 +192,7 @@ trait MockAccountData
|
|||||||
|
|
||||||
$settings = CompanySettings::defaults();
|
$settings = CompanySettings::defaults();
|
||||||
|
|
||||||
$settings->company_logo = 'https://app.invoiceninja.com/favicon-v2.png';
|
$settings->company_logo = 'https://pdf.invoicing.co/favicon-v2.png';
|
||||||
// $settings->company_logo = asset('images/new_logo.png');
|
// $settings->company_logo = asset('images/new_logo.png');
|
||||||
$settings->website = 'www.invoiceninja.com';
|
$settings->website = 'www.invoiceninja.com';
|
||||||
$settings->address1 = 'Address 1';
|
$settings->address1 = 'Address 1';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user