mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-04 01:17:30 -05:00 
			
		
		
		
	
						commit
						413eadd6fb
					
				@ -1 +1 @@
 | 
			
		||||
5.7.42
 | 
			
		||||
5.7.43
 | 
			
		||||
@ -41,6 +41,9 @@ class ExpenseFilters extends QueryFilters
 | 
			
		||||
                ->orWhere('custom_value4', 'like', '%'.$filter.'%')
 | 
			
		||||
                ->orWhereHas('category', function ($q) use ($filter) {
 | 
			
		||||
                    $q->where('name', 'like', '%'.$filter.'%');
 | 
			
		||||
                })
 | 
			
		||||
                ->orWhereHas('vendor', function ($q) use ($filter) {
 | 
			
		||||
                    $q->where('name', 'like', '%'.$filter.'%');
 | 
			
		||||
                });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -154,23 +154,15 @@ class UserFilters extends QueryFilters
 | 
			
		||||
            $user = auth()->user();
 | 
			
		||||
 | 
			
		||||
            if (in_array(self::STATUS_ACTIVE, $filters)) {
 | 
			
		||||
                $query = $query->orWhereHas('company_users', function ($q) use($user){
 | 
			
		||||
                    $q->where('company_id', $user->company()->id)->whereNull('deleted_at');
 | 
			
		||||
                });
 | 
			
		||||
                $query->orWhereNull('deleted_at');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (in_array(self::STATUS_ARCHIVED, $filters)) {
 | 
			
		||||
                $query = $query->orWhereHas('company_users', function ($q) use($user){
 | 
			
		||||
                    $q->where('company_id', $user->company()->id)->whereNotNull('deleted_at')->where('is_deleted', 0);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                $query->orWhereNotNull('deleted_at')->where('is_deleted', 0);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (in_array(self::STATUS_DELETED, $filters)) {
 | 
			
		||||
                $query = $query->orWhereHas('company_users', function ($q) use($user){
 | 
			
		||||
                     $q->where('company_id', $user->company()->id)->where('is_deleted', 1);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                $query->orWhere('is_deleted', 1);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1123,10 +1123,10 @@ class BaseController extends Controller
 | 
			
		||||
            $data['white_label'] = Ninja::isSelfHost() ? $account->isPaid() : false;
 | 
			
		||||
 | 
			
		||||
            //pass referral code to front end
 | 
			
		||||
            $data['rc'] = request()->has('rc') ? request()->input('rc') : '';
 | 
			
		||||
            $data['build'] = request()->has('build') ? request()->input('build') : '';
 | 
			
		||||
            $data['login'] = request()->has('login') ? request()->input('login') : 'false';
 | 
			
		||||
            $data['signup'] = request()->has('signup') ? request()->input('signup') : 'false';
 | 
			
		||||
            $data['rc'] = request()->has('rc') && is_string(request()->input('rc')) ? request()->input('rc') : '';
 | 
			
		||||
            $data['build'] = request()->has('build') && is_string(request()->input('build')) ? request()->input('build') : '';
 | 
			
		||||
            $data['login'] = request()->has('login') && is_string(request()->input('input')) ? request()->input('login') : 'false';
 | 
			
		||||
            $data['signup'] = request()->has('signup') && is_string(request()->input('signup')) ? request()->input('signup') : 'false';
 | 
			
		||||
            $data['canvas_path'] = $canvas_path;
 | 
			
		||||
 | 
			
		||||
            if (request()->session()->has('login')) {
 | 
			
		||||
 | 
			
		||||
@ -181,6 +181,16 @@ class InvoiceController extends Controller
 | 
			
		||||
                ->with('message', ctrans('texts.no_payable_invoices_selected'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //ensure all stale fees are removed.
 | 
			
		||||
        $invoices->each(function ($invoice) {
 | 
			
		||||
            $invoice->service()
 | 
			
		||||
                    ->markSent()
 | 
			
		||||
                    ->removeUnpaidGatewayFees()
 | 
			
		||||
                    ->save();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $invoices = $invoices->fresh();
 | 
			
		||||
 | 
			
		||||
        //iterate and sum the payable amounts either partial or balance
 | 
			
		||||
        $total = 0;
 | 
			
		||||
        foreach ($invoices as $invoice) {
 | 
			
		||||
 | 
			
		||||
@ -11,27 +11,28 @@
 | 
			
		||||
 | 
			
		||||
namespace App\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use App\Events\Expense\ExpenseWasCreated;
 | 
			
		||||
use App\Events\Expense\ExpenseWasUpdated;
 | 
			
		||||
use App\Utils\Ninja;
 | 
			
		||||
use App\Models\Account;
 | 
			
		||||
use App\Models\Expense;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
use App\Factory\ExpenseFactory;
 | 
			
		||||
use App\Filters\ExpenseFilters;
 | 
			
		||||
use App\Http\Requests\Expense\CreateExpenseRequest;
 | 
			
		||||
use App\Http\Requests\Expense\DestroyExpenseRequest;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use App\Utils\Traits\Uploadable;
 | 
			
		||||
use App\Utils\Traits\BulkOptions;
 | 
			
		||||
use App\Utils\Traits\SavesDocuments;
 | 
			
		||||
use App\Repositories\ExpenseRepository;
 | 
			
		||||
use App\Transformers\ExpenseTransformer;
 | 
			
		||||
use App\Events\Expense\ExpenseWasCreated;
 | 
			
		||||
use App\Events\Expense\ExpenseWasUpdated;
 | 
			
		||||
use App\Http\Requests\Expense\BulkExpenseRequest;
 | 
			
		||||
use App\Http\Requests\Expense\EditExpenseRequest;
 | 
			
		||||
use App\Http\Requests\Expense\ShowExpenseRequest;
 | 
			
		||||
use App\Http\Requests\Expense\StoreExpenseRequest;
 | 
			
		||||
use App\Http\Requests\Expense\CreateExpenseRequest;
 | 
			
		||||
use App\Http\Requests\Expense\UpdateExpenseRequest;
 | 
			
		||||
use App\Http\Requests\Expense\UploadExpenseRequest;
 | 
			
		||||
use App\Models\Account;
 | 
			
		||||
use App\Models\Expense;
 | 
			
		||||
use App\Repositories\ExpenseRepository;
 | 
			
		||||
use App\Transformers\ExpenseTransformer;
 | 
			
		||||
use App\Utils\Ninja;
 | 
			
		||||
use App\Utils\Traits\BulkOptions;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use App\Utils\Traits\SavesDocuments;
 | 
			
		||||
use App\Utils\Traits\Uploadable;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
use App\Http\Requests\Expense\DestroyExpenseRequest;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ExpenseController.
 | 
			
		||||
@ -321,7 +322,10 @@ class ExpenseController extends BaseController
 | 
			
		||||
     */
 | 
			
		||||
    public function create(CreateExpenseRequest $request)
 | 
			
		||||
    {
 | 
			
		||||
        $expense = ExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id);
 | 
			
		||||
        /** @var \App\Models\User $user */
 | 
			
		||||
        $user = auth()->user();
 | 
			
		||||
 | 
			
		||||
        $expense = ExpenseFactory::create($user->company()->id, $user->id);
 | 
			
		||||
 | 
			
		||||
        return $this->itemResponse($expense);
 | 
			
		||||
    }
 | 
			
		||||
@ -366,9 +370,12 @@ class ExpenseController extends BaseController
 | 
			
		||||
     */
 | 
			
		||||
    public function store(StoreExpenseRequest $request)
 | 
			
		||||
    {
 | 
			
		||||
        $expense = $this->expense_repo->save($request->all(), ExpenseFactory::create(auth()->user()->company()->id, auth()->user()->id));
 | 
			
		||||
        /** @var \App\Models\User $user */
 | 
			
		||||
        $user = auth()->user();
 | 
			
		||||
 | 
			
		||||
        event(new ExpenseWasCreated($expense, $expense->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
 | 
			
		||||
        $expense = $this->expense_repo->save($request->all(), ExpenseFactory::create($user->company()->id, $user->id));
 | 
			
		||||
 | 
			
		||||
        event(new ExpenseWasCreated($expense, $expense->company, Ninja::eventVars($user ? $user->id : null)));
 | 
			
		||||
 | 
			
		||||
        event('eloquent.created: App\Models\Expense', $expense);
 | 
			
		||||
 | 
			
		||||
@ -481,20 +488,25 @@ class ExpenseController extends BaseController
 | 
			
		||||
     *       ),
 | 
			
		||||
     *     )
 | 
			
		||||
     */
 | 
			
		||||
    public function bulk()
 | 
			
		||||
    public function bulk(BulkExpenseRequest $request)
 | 
			
		||||
    {
 | 
			
		||||
        $action = request()->input('action');
 | 
			
		||||
        /** @var \App\Models\User $user */
 | 
			
		||||
        $user = auth()->user();
 | 
			
		||||
 | 
			
		||||
        $ids = request()->input('ids');
 | 
			
		||||
        $expenses = Expense::withTrashed()->find($this->transformKeys($ids));
 | 
			
		||||
        $expenses = Expense::withTrashed()->find($request->ids);
 | 
			
		||||
 | 
			
		||||
        $expenses->each(function ($expense, $key) use ($action) {
 | 
			
		||||
            if (auth()->user()->can('edit', $expense)) {
 | 
			
		||||
                $this->expense_repo->{$action}($expense);
 | 
			
		||||
        if($request->action == 'bulk_categorize' && $user->can('edit', $expenses->first())) {
 | 
			
		||||
            $this->expense_repo->categorize($expenses, $request->category_id);
 | 
			
		||||
            $expenses = collect([]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $expenses->each(function ($expense) use ($request, $user) {
 | 
			
		||||
            if ($user->can('edit', $expense)) {
 | 
			
		||||
                $this->expense_repo->{$request->action}($expense);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return $this->listResponse(Expense::withTrashed()->whereIn('id', $this->transformKeys($ids)));
 | 
			
		||||
        return $this->listResponse(Expense::withTrashed()->whereIn('id', $request->ids));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -55,6 +55,9 @@ class ImportJsonController extends BaseController
 | 
			
		||||
     */
 | 
			
		||||
    public function import(ImportJsonRequest $request)
 | 
			
		||||
    {
 | 
			
		||||
        /** @var \App\Models\User $user */
 | 
			
		||||
        $user = auth()->user();
 | 
			
		||||
 | 
			
		||||
        $file_location = $request->file('files')
 | 
			
		||||
            ->storeAs(
 | 
			
		||||
                'migrations',
 | 
			
		||||
@ -63,9 +66,9 @@ class ImportJsonController extends BaseController
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
        if (Ninja::isHosted()) {
 | 
			
		||||
            CompanyImport::dispatch(auth()->user()->getCompany(), auth()->user(), $file_location, $request->except('files'))->onQueue('migration');
 | 
			
		||||
            CompanyImport::dispatch($user->company(), $user, $file_location, $request->except('files'))->onQueue('migration');
 | 
			
		||||
        } else {
 | 
			
		||||
            CompanyImport::dispatch(auth()->user()->getCompany(), auth()->user(), $file_location, $request->except('files'));
 | 
			
		||||
            CompanyImport::dispatch($user->company(), $user, $file_location, $request->except('files'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(['message' => 'Processing'], 200);
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@ class SubdomainController extends BaseController
 | 
			
		||||
    public function index()
 | 
			
		||||
    {
 | 
			
		||||
        if (!MultiDB::checkDomainAvailable(request()->input('subdomain'))) {
 | 
			
		||||
            return response()->json(['message' => 'Domain not available'], 401);
 | 
			
		||||
            return response()->json(['message' => ctrans('texts.subdomain_is_not_available')], 401); 
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(['message' => 'Domain available'], 200);
 | 
			
		||||
 | 
			
		||||
@ -12,13 +12,10 @@
 | 
			
		||||
namespace App\Http\Requests\Expense;
 | 
			
		||||
 | 
			
		||||
use App\Http\Requests\Request;
 | 
			
		||||
use App\Models\Expense;
 | 
			
		||||
use App\Utils\Traits\BulkOptions;
 | 
			
		||||
use Illuminate\Validation\Rule;
 | 
			
		||||
 | 
			
		||||
class BulkExpenseRequest extends Request
 | 
			
		||||
{
 | 
			
		||||
    use BulkOptions;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determine if the user is authorized to make this request.
 | 
			
		||||
     *
 | 
			
		||||
@ -26,15 +23,7 @@ class BulkExpenseRequest extends Request
 | 
			
		||||
     */
 | 
			
		||||
    public function authorize()
 | 
			
		||||
    {
 | 
			
		||||
        if (! $this->has('action')) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (! in_array($this->action, $this->getBulkOptions(), true)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return auth()->user()->can(auth()->user()->isAdmin(), Expense::class);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -44,13 +33,30 @@ class BulkExpenseRequest extends Request
 | 
			
		||||
     */
 | 
			
		||||
    public function rules()
 | 
			
		||||
    {
 | 
			
		||||
        $rules = $this->getGlobalRules();
 | 
			
		||||
        /** @var \App\Models\User $user */
 | 
			
		||||
        $user = auth()->user();
 | 
			
		||||
 | 
			
		||||
        /* We don't require IDs on bulk storing. */
 | 
			
		||||
        if ($this->action !== self::$STORE_METHOD) {
 | 
			
		||||
            $rules['ids'] = ['required'];
 | 
			
		||||
        return [
 | 
			
		||||
            'ids' => ['required','bail','array', Rule::exists('expenses', 'id')->where('company_id', $user->company()->id)],
 | 
			
		||||
            'category_id' => ['sometimes', 'bail', Rule::exists('expense_categories', 'id')->where('company_id', $user->company()->id)],
 | 
			
		||||
            'action' => 'in:archive,restore,delete,bulk_categorize',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function prepareForValidation()
 | 
			
		||||
    {
 | 
			
		||||
        $input = $this->all();
 | 
			
		||||
 | 
			
		||||
        if (isset($input['ids'])) {
 | 
			
		||||
            $input['ids'] = $this->transformKeys($input['ids']);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $rules;
 | 
			
		||||
        if (isset($input['category_id'])) {
 | 
			
		||||
            $input['category_id'] = $this->transformKeys($input['category_id']);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->replace($input);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -82,6 +82,8 @@ class StoreRecurringInvoiceRequest extends Request
 | 
			
		||||
    public function prepareForValidation()
 | 
			
		||||
    {
 | 
			
		||||
        $input = $this->all();
 | 
			
		||||
        $input['amount'] = 0;
 | 
			
		||||
        $input['balance'] = 0;
 | 
			
		||||
 | 
			
		||||
        if (array_key_exists('due_date_days', $input) && is_null($input['due_date_days'])) {
 | 
			
		||||
            $input['due_date_days'] = 'terms';
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,10 @@ class StoreSchedulerRequest extends Request
 | 
			
		||||
     */
 | 
			
		||||
    public function authorize(): bool
 | 
			
		||||
    {
 | 
			
		||||
        return auth()->user()->isAdmin();
 | 
			
		||||
        /** @var \App\Models\User $user */
 | 
			
		||||
        $user = auth()->user();
 | 
			
		||||
 | 
			
		||||
        return $user->isAdmin();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function rules()
 | 
			
		||||
 | 
			
		||||
@ -22,7 +22,10 @@ class UpdateSchedulerRequest extends Request
 | 
			
		||||
     */
 | 
			
		||||
    public function authorize(): bool
 | 
			
		||||
    {
 | 
			
		||||
        return auth()->user()->isAdmin() && $this->task_scheduler->company_id == auth()->user()->company()->id;
 | 
			
		||||
        /** @var \App\Models\User $user */
 | 
			
		||||
        $user = auth()->user();
 | 
			
		||||
 | 
			
		||||
        return $user->isAdmin() && $this->task_scheduler->company_id == $user->company()->id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function rules(): array
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,10 @@ class ValidClientIds implements Rule
 | 
			
		||||
     */
 | 
			
		||||
    public function passes($attribute, $value)
 | 
			
		||||
    {
 | 
			
		||||
        return Client::where('company_id', auth()->user()->company()->id)->whereIn('id', $this->transformKeys($value))->count() == count($value);
 | 
			
		||||
        /** @var \App\Models\User $user */
 | 
			
		||||
        $user = auth()->user();
 | 
			
		||||
 | 
			
		||||
        return Client::where('company_id', $user->company()->id)->whereIn('id', $this->transformKeys($value))->count() == count($value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -201,7 +201,7 @@ class CompanyExport implements ShouldQueue
 | 
			
		||||
            return $document->makeVisible(['id']);
 | 
			
		||||
        })->all();
 | 
			
		||||
 | 
			
		||||
        $this->export_data['expense_categories'] = $this->company->expense_categories->map(function ($expense_category) {
 | 
			
		||||
        $this->export_data['expense_categories'] = $this->company->expense_categories()->cursor()->map(function ($expense_category) {
 | 
			
		||||
            $expense_category = $this->transformArrayOfKeys($expense_category, ['user_id', 'company_id']);
 | 
			
		||||
            
 | 
			
		||||
            return $expense_category->makeVisible(['id']);
 | 
			
		||||
@ -399,6 +399,12 @@ class CompanyExport implements ShouldQueue
 | 
			
		||||
            return $bank_transaction->makeVisible(['id','user_id','company_id']);
 | 
			
		||||
        })->all();
 | 
			
		||||
 | 
			
		||||
        $this->export_data['schedulers'] = $this->company->schedulers()->orderBy('id', 'ASC')->cursor()->map(function ($scheduler) {
 | 
			
		||||
            $scheduler = $this->transformArrayOfKeys($scheduler, ['company_id', 'user_id']);
 | 
			
		||||
 | 
			
		||||
            return $scheduler->makeVisible(['id','user_id','company_id']);
 | 
			
		||||
        })->all();
 | 
			
		||||
 | 
			
		||||
        //write to tmp and email to owner();
 | 
			
		||||
        
 | 
			
		||||
        $this->zipAndSend();
 | 
			
		||||
@ -440,7 +446,7 @@ class CompanyExport implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
        $path = 'backups';
 | 
			
		||||
 | 
			
		||||
        Storage::makeDirectory(storage_path('backups/'));
 | 
			
		||||
        // Storage::makeDirectory(storage_path('backups/'));
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            mkdir(storage_path('backups/'));
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@ use App\Exceptions\NonExistingMigrationFile;
 | 
			
		||||
use App\Factory\ClientContactFactory;
 | 
			
		||||
use App\Jobs\Mail\NinjaMailerJob;
 | 
			
		||||
use App\Jobs\Mail\NinjaMailerObject;
 | 
			
		||||
use App\Jobs\Ninja\TaskScheduler;
 | 
			
		||||
use App\Libraries\MultiDB;
 | 
			
		||||
use App\Mail\Import\CompanyImportFailure;
 | 
			
		||||
use App\Mail\Import\ImportCompleted;
 | 
			
		||||
@ -111,6 +112,8 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    private $file_path;
 | 
			
		||||
 | 
			
		||||
    private string $import_version = '';
 | 
			
		||||
 | 
			
		||||
    private $importables = [
 | 
			
		||||
        // 'company',
 | 
			
		||||
        'users',
 | 
			
		||||
@ -151,6 +154,7 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
        'bank_integrations',
 | 
			
		||||
        'bank_transactions',
 | 
			
		||||
        'payments',
 | 
			
		||||
        'schedulers',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    private $company_properties = [
 | 
			
		||||
@ -210,6 +214,22 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
        "convert_rate_to_client",
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    private array $version_keys = [
 | 
			
		||||
        'baseline' => [],
 | 
			
		||||
        '5.7.35' => [
 | 
			
		||||
            Payment::class => [
 | 
			
		||||
                'refund_meta', 
 | 
			
		||||
                'category_id',
 | 
			
		||||
            ],
 | 
			
		||||
            User::class => [
 | 
			
		||||
                'user_logged_in_notification',
 | 
			
		||||
            ],
 | 
			
		||||
            Design::class => [
 | 
			
		||||
                'is_template',
 | 
			
		||||
            ]
 | 
			
		||||
        ],
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new job instance.
 | 
			
		||||
     *
 | 
			
		||||
@ -407,9 +427,7 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
        $data = (object)$this->getObject('app_version', true);
 | 
			
		||||
        
 | 
			
		||||
        if ($this->current_app_version != $data->app_version) {
 | 
			
		||||
            //perform some magic here
 | 
			
		||||
        }
 | 
			
		||||
        $this->import_version = $data->app_version;
 | 
			
		||||
        
 | 
			
		||||
        if ($this->pre_flight_checks_pass === false) {
 | 
			
		||||
            $this->sendImportMail($this->message);
 | 
			
		||||
@ -439,10 +457,12 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
        $settings->project_number_counter = 1;
 | 
			
		||||
        $settings->purchase_order_number_counter = 1;
 | 
			
		||||
        $this->company->settings = $co->settings;
 | 
			
		||||
        // $this->company->settings = $this->backup_file->company->settings;
 | 
			
		||||
 | 
			
		||||
        $this->company->saveSettings($co->settings, $this->company);
 | 
			
		||||
 | 
			
		||||
        $this->company->save();
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
            return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function purgeCompanyData()
 | 
			
		||||
@ -456,6 +476,10 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
        $this->company->expenses()->forceDelete();
 | 
			
		||||
        $this->company->subscriptions()->forceDelete();
 | 
			
		||||
        $this->company->purchase_orders()->forceDelete();
 | 
			
		||||
        $this->company->bank_integrations()->forceDelete();
 | 
			
		||||
        $this->company->bank_transactions()->forceDelete();
 | 
			
		||||
        $this->company->schedulers()->forceDelete();
 | 
			
		||||
        $this->company->system_log_relation()->forceDelete();
 | 
			
		||||
 | 
			
		||||
        $this->company->save();
 | 
			
		||||
 | 
			
		||||
@ -507,6 +531,20 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function import_schedulers()
 | 
			
		||||
    {
 | 
			
		||||
        $this->genericNewClassImport(
 | 
			
		||||
            \App\Models\Scheduler::class,
 | 
			
		||||
            ['company_id', 'id', 'hashed_id'],
 | 
			
		||||
            [
 | 
			
		||||
                ['users' => 'user_id'],
 | 
			
		||||
            ],
 | 
			
		||||
            'schedulers'
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function import_bank_integrations()
 | 
			
		||||
    {
 | 
			
		||||
        $this->genericImport(
 | 
			
		||||
@ -1132,7 +1170,6 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
            $new_document->save(['timestamps' => false]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            $storage_url = (object)$this->getObject('storage_url', true);
 | 
			
		||||
 | 
			
		||||
            if (!Storage::exists($new_document->url) && is_string($storage_url)) {
 | 
			
		||||
@ -1327,6 +1364,35 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function filterVersionProps($class, array $obj_array): array
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        if($this->current_app_version == $this->import_version)
 | 
			
		||||
            return $obj_array;
 | 
			
		||||
 | 
			
		||||
        $version_index = 0;
 | 
			
		||||
        $index = 0;
 | 
			
		||||
 | 
			
		||||
        $filters = collect($this->version_keys)
 | 
			
		||||
            ->map(function ($value, $key) use (&$version_index, &$index) {
 | 
			
		||||
                if($this->import_version == $key) {
 | 
			
		||||
                    $version_index = $index;
 | 
			
		||||
                }
 | 
			
		||||
                                                            
 | 
			
		||||
                $index++;
 | 
			
		||||
                return $value;
 | 
			
		||||
 | 
			
		||||
            })
 | 
			
		||||
            ->when($version_index == 0, function ($collection) {
 | 
			
		||||
                return collect([]);
 | 
			
		||||
            })
 | 
			
		||||
            ->when($version_index > 0, function ($collection) use (&$version_index, $class) {
 | 
			
		||||
                return $collection->slice($version_index)->pluck($class)->filter();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return collect($obj_array)->diffKeys($filters->flatten()->flip())->toArray();
 | 
			
		||||
 | 
			
		||||
    } 
 | 
			
		||||
        
 | 
			
		||||
    private function genericNewClassImport($class, $unset, $transforms, $object_property)
 | 
			
		||||
    {
 | 
			
		||||
@ -1348,6 +1414,10 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
                if (Ninja::isSelfHost() && $obj_array['gateway_key'] == 'd14dd26a47cecc30fdd65700bfb67b34') {
 | 
			
		||||
                    $obj_array['gateway_key'] = 'd14dd26a37cecc30fdd65700bfb55b23';
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if(!isset($obj_array['fees_and_limits'])){
 | 
			
		||||
                    $obj_array['fees_and_limits'] = \json_encode([]);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (array_key_exists('deleted_at', $obj_array) && $obj_array['deleted_at'] > 1) {
 | 
			
		||||
@ -1385,8 +1455,29 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
                $obj_array['config'] = encrypt($obj_array['config']);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if($class == 'App\Models\Scheduler') {
 | 
			
		||||
                $parameters = $obj_array['parameters'];
 | 
			
		||||
 | 
			
		||||
                if(isset($parameters->clients)){
 | 
			
		||||
 | 
			
		||||
                    $parameters->clients =
 | 
			
		||||
                    collect($parameters->clients)->map(function ($client_hash){
 | 
			
		||||
                        return $this->encodePrimaryKey($this->transformId('clients', $client_hash));
 | 
			
		||||
                    })->toArray();
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if(isset($parameters->entity_id)){
 | 
			
		||||
                    $parameters->entity_id = $this->encodePrimaryKey($this->transformId($parameters->entity."s", $parameters->entity_id));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $obj_array['parameters'] = $parameters;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $new_obj = new $class();
 | 
			
		||||
            $new_obj->company_id = $this->company->id;
 | 
			
		||||
            $obj_array = $this->filterVersionProps($class,$obj_array);
 | 
			
		||||
 | 
			
		||||
            $new_obj->fill($obj_array);
 | 
			
		||||
 | 
			
		||||
            $new_obj->save(['timestamps' => false]);
 | 
			
		||||
@ -1431,6 +1522,8 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
                $obj_array['webhook_configuration'] = \json_encode($obj_array['webhook_configuration']);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            $obj_array = $this->filterVersionProps($class, $obj_array);
 | 
			
		||||
 | 
			
		||||
            $new_obj = $class::firstOrNew(
 | 
			
		||||
                [$match_key => $obj->{$match_key}],
 | 
			
		||||
                $obj_array,
 | 
			
		||||
@ -1482,6 +1575,8 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
                $obj_array['product_ids'] = '';
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            $obj_array = $this->filterVersionProps($class, $obj_array);
 | 
			
		||||
 | 
			
		||||
            /* Expenses that don't have a number will not be inserted - so need to override here*/
 | 
			
		||||
            if ($class == 'App\Models\Expense' && is_null($obj->{$match_key})) {
 | 
			
		||||
                $new_obj = new Expense();
 | 
			
		||||
 | 
			
		||||
@ -743,12 +743,26 @@ class BaseDriver extends AbstractPaymentDriver
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $invoices_string = str_replace(["*","<",">","'",'"'], "-", $invoices_string);
 | 
			
		||||
        // $invoices_string = "I-".$invoices_string;
 | 
			
		||||
        // $invoices_string = substr($invoices_string, 0, 22);
 | 
			
		||||
        
 | 
			
		||||
        $invoices_string = "I-".$invoices_string;
 | 
			
		||||
// 2023-11-02 - improve the statement descriptor for string
 | 
			
		||||
$company_name = $this->client->company->present()->name();
 | 
			
		||||
 | 
			
		||||
        $invoices_string = substr($invoices_string, 0, 22);
 | 
			
		||||
if(ctype_digit(substr($company_name, 0, 1)))
 | 
			
		||||
    $company_name = "X" . $company_name;
 | 
			
		||||
 | 
			
		||||
        $invoices_string = str_pad($invoices_string, 5, ctrans('texts.invoice'), STR_PAD_LEFT);
 | 
			
		||||
$suffix = strlen($invoices_string) + 1;
 | 
			
		||||
 | 
			
		||||
$length = 22 - $suffix;
 | 
			
		||||
 | 
			
		||||
$company_name = substr($company_name, 0, $length);
 | 
			
		||||
 | 
			
		||||
$descriptor = "{$company_name} {$invoices_string}";
 | 
			
		||||
 | 
			
		||||
$invoices_string = str_pad($descriptor, 5, ctrans('texts.invoice'), STR_PAD_RIGHT);
 | 
			
		||||
 | 
			
		||||
        // $invoices_string = str_pad($invoices_string, 5, ctrans('texts.invoice'), STR_PAD_LEFT);
 | 
			
		||||
 | 
			
		||||
        return $invoices_string;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -51,34 +51,6 @@ class DirectDebit implements MethodInterface
 | 
			
		||||
    public function authorizeView(array $data)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->billingRequestFlows($data);
 | 
			
		||||
        // $session_token = \Illuminate\Support\Str::uuid()->toString();
 | 
			
		||||
 | 
			
		||||
        // try {
 | 
			
		||||
        //     $redirect = $this->go_cardless->gateway->redirectFlows()->create([
 | 
			
		||||
        //         'params' => [
 | 
			
		||||
        //             'session_token' => $session_token,
 | 
			
		||||
        //             'success_redirect_url' => route('client.payment_methods.confirm', [
 | 
			
		||||
        //                 'method' => GatewayType::DIRECT_DEBIT,
 | 
			
		||||
        //                 'session_token' => $session_token,
 | 
			
		||||
        //             ]),
 | 
			
		||||
        //             'prefilled_customer' => [
 | 
			
		||||
        //                 'given_name' => auth()->guard('contact')->user()->first_name ?: '',
 | 
			
		||||
        //                 'family_name' => auth()->guard('contact')->user()->last_name ?: '',
 | 
			
		||||
        //                 'email' => auth()->guard('contact')->user()->email ?: '',
 | 
			
		||||
        //                 'address_line1' => auth()->guard('contact')->user()->client->address1 ?: '',
 | 
			
		||||
        //                 'city' => auth()->guard('contact')->user()->client->city ?: '',
 | 
			
		||||
        //                 'postal_code' => auth()->guard('contact')->user()->client->postal_code ?: '',
 | 
			
		||||
        //                 'country_code' => auth()->guard('contact')->user()->client->country->iso_3166_2,
 | 
			
		||||
        //             ],
 | 
			
		||||
        //         ],
 | 
			
		||||
        //     ]);
 | 
			
		||||
 | 
			
		||||
        //     return redirect(
 | 
			
		||||
        //         $redirect->redirect_url
 | 
			
		||||
        //     );
 | 
			
		||||
        // } catch (\Exception $exception) {
 | 
			
		||||
        //     return $this->processUnsuccessfulAuthorization($exception);
 | 
			
		||||
        // }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -109,7 +81,7 @@ class DirectDebit implements MethodInterface
 | 
			
		||||
                        "params" => [
 | 
			
		||||
                            "mandate_request" => [
 | 
			
		||||
                            "currency" => auth()->guard('contact')->user()->client->currency()->code,
 | 
			
		||||
                            "verify" => "recommended"
 | 
			
		||||
                            "verify" => "when_available"
 | 
			
		||||
                            ]
 | 
			
		||||
                        ]
 | 
			
		||||
                    ]);
 | 
			
		||||
 | 
			
		||||
@ -404,7 +404,9 @@ class GoCardlessPaymentDriver extends BaseDriver
 | 
			
		||||
            $this->init();
 | 
			
		||||
            $mandate = $this->gateway->mandates()->get($token);
 | 
			
		||||
 | 
			
		||||
            if ($mandate->status !== 'active') {
 | 
			
		||||
            if(!in_array($mandate->status, ['pending_submission', 'submitted', 'active','pending_customer_approval'])) {
 | 
			
		||||
             
 | 
			
		||||
            // if ($mandate->status !== 'active') {
 | 
			
		||||
                throw new \Exception(ctrans('texts.gocardless_mandate_not_ready'));
 | 
			
		||||
            }
 | 
			
		||||
        } catch (\Exception $exception) {
 | 
			
		||||
 | 
			
		||||
@ -199,7 +199,7 @@ class BaseRepository
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
nlog($model->toArray());
 | 
			
		||||
        $model->saveQuietly();
 | 
			
		||||
 | 
			
		||||
        /* Model now persisted, now lets do some child tasks */
 | 
			
		||||
 | 
			
		||||
@ -12,13 +12,15 @@
 | 
			
		||||
 | 
			
		||||
namespace App\Repositories;
 | 
			
		||||
 | 
			
		||||
use App\Factory\ExpenseFactory;
 | 
			
		||||
use App\Libraries\Currency\Conversion\CurrencyApi;
 | 
			
		||||
use App\Models\Expense;
 | 
			
		||||
use App\Utils\Traits\GeneratesCounter;
 | 
			
		||||
use Carbon\Exceptions\InvalidFormatException;
 | 
			
		||||
use Illuminate\Database\QueryException;
 | 
			
		||||
use Illuminate\Support\Carbon;
 | 
			
		||||
use App\Factory\ExpenseFactory;
 | 
			
		||||
use App\Models\ExpenseCategory;
 | 
			
		||||
use App\Utils\Traits\GeneratesCounter;
 | 
			
		||||
use Illuminate\Database\QueryException;
 | 
			
		||||
use Carbon\Exceptions\InvalidFormatException;
 | 
			
		||||
use App\Libraries\Currency\Conversion\CurrencyApi;
 | 
			
		||||
use Illuminate\Database\Eloquent\Collection;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ExpenseRepository.
 | 
			
		||||
@ -158,4 +160,25 @@ class ExpenseRepository extends BaseRepository
 | 
			
		||||
 | 
			
		||||
        return $expense;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Categorize Expenses in bulk
 | 
			
		||||
     *
 | 
			
		||||
     * @param  Collection $expenses
 | 
			
		||||
     * @param  int $category_id
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function categorize(Collection $expenses, int $category_id): void
 | 
			
		||||
    {
 | 
			
		||||
        $ec = ExpenseCategory::withTrashed()->find($category_id);
 | 
			
		||||
 | 
			
		||||
            $expenses->when($ec)
 | 
			
		||||
                     ->each(function ($expense) use($ec){
 | 
			
		||||
                                                
 | 
			
		||||
                        $expense->category_id = $ec->id;
 | 
			
		||||
                        $expense->save();
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -175,15 +175,13 @@ class FacturaEInvoice extends AbstractService
 | 
			
		||||
             ->setBillingPeriod()
 | 
			
		||||
             ->signDocument();
 | 
			
		||||
 | 
			
		||||
        $disk = config('filesystems.default');
 | 
			
		||||
        // $disk = config('filesystems.default');
 | 
			
		||||
 | 
			
		||||
        if (!Storage::disk($disk)->exists($this->invoice->client->e_invoice_filepath($this->invoice->invitations->first()))) {
 | 
			
		||||
            Storage::makeDirectory($this->invoice->client->e_invoice_filepath($this->invoice->invitations->first()));
 | 
			
		||||
        }
 | 
			
		||||
        // if (!Storage::disk($disk)->exists($this->invoice->client->e_invoice_filepath($this->invoice->invitations->first()))) {
 | 
			
		||||
        //     Storage::makeDirectory($this->invoice->client->e_invoice_filepath($this->invoice->invitations->first()));
 | 
			
		||||
        // }
 | 
			
		||||
 | 
			
		||||
        // $this->fac->export(Storage::disk($disk)->path($this->invoice->client->e_invoice_filepath($this->invoice->invitations->first()) . $this->invoice->getFileName("xsig")));
 | 
			
		||||
        return $this->fac->export();
 | 
			
		||||
        // return $this->invoice->client->e_invoice_filepath($this->invoice->invitations->first()) . $this->invoice->getFileName("xsig");
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -546,8 +544,8 @@ class FacturaEInvoice extends AbstractService
 | 
			
		||||
        "isLegalEntity" => $this->invoice->client->classification === 'individual' ? false : true,
 | 
			
		||||
        "taxNumber"     => $this->invoice->client->vat_number,
 | 
			
		||||
        "name"          => substr($this->invoice->client->present()->name(), 0, 40),
 | 
			
		||||
        "firstSurname"  => substr($this->invoice->client->present()->first_name(), 0, 40),
 | 
			
		||||
        "lastSurname"   => substr($this->invoice->client->present()->last_name(), 0, 40),
 | 
			
		||||
        // "firstSurname"  => substr($this->invoice->client->present()->last_name(), 0, 40),
 | 
			
		||||
        // "lastSurname"   => substr($this->invoice->client->present()->last_name(), 0, 40),
 | 
			
		||||
        "address"       => substr($this->invoice->client->address1, 0, 80),
 | 
			
		||||
        "postCode"      => substr($this->invoice->client->postal_code, 0, 5),
 | 
			
		||||
        "town"          => substr($this->invoice->client->city, 0, 50),
 | 
			
		||||
@ -563,6 +561,11 @@ class FacturaEInvoice extends AbstractService
 | 
			
		||||
        // "ineTownCode" => "280796" // Cód. de municipio del INE
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        if($this->invoice->client->classification === 'individual') {
 | 
			
		||||
            $buyer['name'] = $this->invoice->client->present()->first_name();
 | 
			
		||||
            $buyer['firstSurname'] = $this->invoice->client->present()->last_name();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->fac->setBuyer($buyer);
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
 | 
			
		||||
@ -442,7 +442,6 @@ class InvoiceService
 | 
			
		||||
        $this->invoice->line_items = array_values($items);
 | 
			
		||||
 | 
			
		||||
        $this->invoice = $this->invoice->calc()->getInvoice();
 | 
			
		||||
        $this->deleteEInvoice(); //@deprecated
 | 
			
		||||
 | 
			
		||||
        /* 24-03-2022 */
 | 
			
		||||
        $new_balance = $this->invoice->balance;
 | 
			
		||||
 | 
			
		||||
@ -522,7 +522,7 @@ class TemplateService
 | 
			
		||||
            'balance_raw' => ($payment->amount - $payment->refunded - $payment->applied),
 | 
			
		||||
            'date' => $this->translateDate($payment->date, $payment->client->date_format(), $payment->client->locale()),
 | 
			
		||||
            'method' => $payment->translatedType(),
 | 
			
		||||
            'currency' => $payment->currency->code,
 | 
			
		||||
            'currency' => $payment->currency->code ?? $payment->company->currency()->code,
 | 
			
		||||
            'exchange_rate' => $payment->exchange_rate,
 | 
			
		||||
            'transaction_reference' => $payment->transaction_reference,
 | 
			
		||||
            'is_manual' => $payment->is_manual,
 | 
			
		||||
 | 
			
		||||
@ -15,11 +15,11 @@ return [
 | 
			
		||||
    'require_https' => env('REQUIRE_HTTPS', true),
 | 
			
		||||
    'app_url' => rtrim(env('APP_URL', ''), '/'),
 | 
			
		||||
    'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
 | 
			
		||||
    'app_version' => env('APP_VERSION','5.7.42'),
 | 
			
		||||
    'app_tag' => env('APP_TAG','5.7.42'),
 | 
			
		||||
    'app_version' => env('APP_VERSION','5.7.43'),
 | 
			
		||||
    'app_tag' => env('APP_TAG','5.7.43'),
 | 
			
		||||
    'minimum_client_version' => '5.0.16',
 | 
			
		||||
    'terms_version' => '1.0.1',
 | 
			
		||||
    'api_secret' => env('API_SECRET', ''),
 | 
			
		||||
    'api_secret' => env('API_SECRET', false),
 | 
			
		||||
    'google_maps_api_key' => env('GOOGLE_MAPS_API_KEY'),
 | 
			
		||||
    'google_analytics_url' => env('GOOGLE_ANALYTICS_URL', 'https://www.google-analytics.com/collect'),
 | 
			
		||||
    'key_length' => 32,
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@ class BankTransactionFactory extends Factory
 | 
			
		||||
            'amount' => $this->faker->randomFloat(2, 10, 10000) ,
 | 
			
		||||
            'currency_id' => '1',
 | 
			
		||||
            'account_type' => 'creditCard',
 | 
			
		||||
            'category_id' => 1,
 | 
			
		||||
            'category_id' => null,
 | 
			
		||||
            'category_type' => 'Random' ,
 | 
			
		||||
            'date' => $this->faker->date('Y-m-d') ,
 | 
			
		||||
            'bank_account_id' => 1 ,
 | 
			
		||||
 | 
			
		||||
@ -11,11 +11,12 @@
 | 
			
		||||
 | 
			
		||||
namespace Tests\Feature;
 | 
			
		||||
 | 
			
		||||
use App\Models\BankIntegration;
 | 
			
		||||
use App\Models\BankTransaction;
 | 
			
		||||
use Tests\TestCase;
 | 
			
		||||
use App\Models\Expense;
 | 
			
		||||
use Tests\MockAccountData;
 | 
			
		||||
use App\Models\BankIntegration;
 | 
			
		||||
use App\Models\BankTransaction;
 | 
			
		||||
use App\Models\ExpenseCategory;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use Illuminate\Database\Eloquent\Model;
 | 
			
		||||
use Illuminate\Support\Facades\Session;
 | 
			
		||||
@ -232,6 +233,42 @@ class ExpenseApiTest extends TestCase
 | 
			
		||||
        $this->assertTrue($arr['data'][0]['is_deleted']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testExpenseBulkCategorize()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $e = Expense::factory()->create([
 | 
			
		||||
            'company_id' => $this->company->id,
 | 
			
		||||
            'user_id' => $this->user->id,
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $ec = ExpenseCategory::factory()->create([
 | 
			
		||||
            'company_id' => $this->company->id,
 | 
			
		||||
            'user_id' => $this->user->id,
 | 
			
		||||
            'name' => 'Test Category',
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        nlog("expense category id = {$ec->hashed_id}");
 | 
			
		||||
 | 
			
		||||
        $data = [
 | 
			
		||||
            'category_id' => $ec->hashed_id,
 | 
			
		||||
            'action' => 'bulk_categorize',
 | 
			
		||||
            'ids' => [$this->encodePrimaryKey($e->id)],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/expenses/bulk', $data);
 | 
			
		||||
 | 
			
		||||
        $arr = $response->json();
 | 
			
		||||
        nlog($arr);
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals($ec->hashed_id, $arr['data'][0]['category_id']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function testAddingExpense()
 | 
			
		||||
    {
 | 
			
		||||
        $data = [
 | 
			
		||||
 | 
			
		||||
@ -195,7 +195,7 @@ class UserTest extends TestCase
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $company_token->token,
 | 
			
		||||
            'X-API-PASSWORD' => 'ALongAndBriliantPassword',
 | 
			
		||||
        ])->get("/api/v1/users?without={$company_token->user->hashed_id}&status=active");
 | 
			
		||||
        ])->get("/api/v1/users?status=active&without={$company_token->user->hashed_id}");
 | 
			
		||||
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
        $this->assertCount(0, $response->json()['data']);
 | 
			
		||||
@ -204,7 +204,7 @@ class UserTest extends TestCase
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $company_token->token,
 | 
			
		||||
            'X-API-PASSWORD' => 'ALongAndBriliantPassword',
 | 
			
		||||
        ])->get("/api/v1/users?without={$company_token->user->hashed_id}&status=archived");
 | 
			
		||||
        ])->get("/api/v1/users?status=archived&without={$company_token->user->hashed_id}");
 | 
			
		||||
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
        $this->assertCount(1, $response->json()['data']);
 | 
			
		||||
@ -213,7 +213,7 @@ class UserTest extends TestCase
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $company_token->token,
 | 
			
		||||
            'X-API-PASSWORD' => 'ALongAndBriliantPassword',
 | 
			
		||||
        ])->get("/api/v1/users?without={$company_token->user->hashed_id}&status=deleted");
 | 
			
		||||
        ])->get("/api/v1/users?status=deleted&without={$company_token->user->hashed_id}");
 | 
			
		||||
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
        $this->assertCount(0, $response->json()['data']);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										242
									
								
								tests/Unit/ArrayFiltersTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								tests/Unit/ArrayFiltersTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,242 @@
 | 
			
		||||
<?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://www.elastic.co/licensing/elastic-license
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Tests\Unit;
 | 
			
		||||
 | 
			
		||||
use Tests\TestCase;
 | 
			
		||||
use App\Models\User;
 | 
			
		||||
use App\Models\Design;
 | 
			
		||||
use App\Models\Payment;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @test
 | 
			
		||||
 */
 | 
			
		||||
class ArrayFiltersTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    private string $import_version = '';
 | 
			
		||||
     
 | 
			
		||||
    private array $version_keys = [
 | 
			
		||||
        'baseline' =>[],
 | 
			
		||||
        '5.7.34' => [
 | 
			
		||||
            Payment::class => [
 | 
			
		||||
                'is_deleted', 
 | 
			
		||||
                'amount',
 | 
			
		||||
            ]
 | 
			
		||||
        ],
 | 
			
		||||
        '5.7.35' => [
 | 
			
		||||
            Payment::class => [
 | 
			
		||||
                'date', 
 | 
			
		||||
                'transaction_reference',
 | 
			
		||||
            ],
 | 
			
		||||
            User::class => [
 | 
			
		||||
                'user_logged_in_notification',
 | 
			
		||||
                'first_name',
 | 
			
		||||
                'last_name',
 | 
			
		||||
            ],
 | 
			
		||||
            Design::class => [
 | 
			
		||||
                'is_template',
 | 
			
		||||
            ]
 | 
			
		||||
        ],
 | 
			
		||||
        '5.7.36' => [
 | 
			
		||||
            Payment::class => [
 | 
			
		||||
                'type_id', 
 | 
			
		||||
                'status_id',
 | 
			
		||||
            ],
 | 
			
		||||
        ],
 | 
			
		||||
        '5.7.37' => [
 | 
			
		||||
            Payment::class => [
 | 
			
		||||
                'currency_id', 
 | 
			
		||||
                'hashed_id',
 | 
			
		||||
            ],
 | 
			
		||||
        ],
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    protected function setUp() :void
 | 
			
		||||
    {
 | 
			
		||||
        parent::setUp();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testPaymentFilterFactory()
 | 
			
		||||
    {
 | 
			
		||||
        $p = Payment::factory()->make()->toArray();
 | 
			
		||||
 | 
			
		||||
        $this->assertIsArray($p);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testPaymentUnsetProps()
 | 
			
		||||
    {
 | 
			
		||||
        $p = Payment::factory()->make()->toArray();
 | 
			
		||||
 | 
			
		||||
        $version = '5.7.36';
 | 
			
		||||
        $current_version = config('ninja.app_version');
 | 
			
		||||
 | 
			
		||||
        $this->assertNotEquals($current_version, $version);
 | 
			
		||||
 | 
			
		||||
        $index = 0;
 | 
			
		||||
        $version_index = 0;
 | 
			
		||||
 | 
			
		||||
        foreach($this->version_keys as $key => $value)
 | 
			
		||||
        {
 | 
			
		||||
            if($version == $key)
 | 
			
		||||
            {
 | 
			
		||||
                $version_index = $index;
 | 
			
		||||
            }
 | 
			
		||||
        
 | 
			
		||||
            $index++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(3, $version_index);
 | 
			
		||||
 | 
			
		||||
        $filters = collect($this->version_keys)->slice($version_index);
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(2, $filters->count());
 | 
			
		||||
 | 
			
		||||
        $x = collect($p)->diffKeys($filters->flatten()->flip());
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(4, $x->count());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testPaymentUnsetPropsScenario2() 
 | 
			
		||||
    {
 | 
			
		||||
        $p = Payment::factory()->make()->toArray();
 | 
			
		||||
 | 
			
		||||
        $version = '5.7.35';
 | 
			
		||||
        $current_version = config('ninja.app_version');
 | 
			
		||||
 | 
			
		||||
        $this->assertNotEquals($current_version, $version);
 | 
			
		||||
 | 
			
		||||
        $index = 0;
 | 
			
		||||
        $version_index = 0;
 | 
			
		||||
 | 
			
		||||
        foreach($this->version_keys as $key => $value)
 | 
			
		||||
        {
 | 
			
		||||
            if($version == $key)
 | 
			
		||||
            {
 | 
			
		||||
                $version_index = $index;
 | 
			
		||||
            }
 | 
			
		||||
        
 | 
			
		||||
            $index++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(2, $version_index);
 | 
			
		||||
        
 | 
			
		||||
        $index = 0;
 | 
			
		||||
        $version_index = 0;
 | 
			
		||||
 | 
			
		||||
        $filters = collect($this->version_keys)
 | 
			
		||||
        ->map(function ($value, $key) use ($version, &$version_index, &$index) {
 | 
			
		||||
            if($version == $key) 
 | 
			
		||||
                $version_index = $index;
 | 
			
		||||
                    
 | 
			
		||||
            $index++;
 | 
			
		||||
            return $value;
 | 
			
		||||
 | 
			
		||||
        })
 | 
			
		||||
        ->slice($version_index)
 | 
			
		||||
        ->pluck(Payment::class);
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(3, $filters->count());
 | 
			
		||||
 | 
			
		||||
        $x = collect($p)->diffKeys($filters->flatten()->flip());
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(2, $x->count());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testWhenScenario() 
 | 
			
		||||
    {
 | 
			
		||||
        $p = Payment::factory()->make()->toArray();
 | 
			
		||||
 | 
			
		||||
        $version = '5.7.35';
 | 
			
		||||
        $current_version = '5.7.35';
 | 
			
		||||
 | 
			
		||||
        $filters = collect($this->version_keys)
 | 
			
		||||
        ->map(function ($value, $key) use ($version, &$version_index, &$index) {
 | 
			
		||||
            if($version == $key) 
 | 
			
		||||
                $version_index = $index;
 | 
			
		||||
                                
 | 
			
		||||
            $index++;
 | 
			
		||||
            return $value;
 | 
			
		||||
 | 
			
		||||
        })
 | 
			
		||||
        ->slice($version_index)
 | 
			
		||||
        ->pluck(Payment::class);
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(3, $filters->count());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testWhenScenario2() 
 | 
			
		||||
    {
 | 
			
		||||
        $p = Payment::factory()->make()->toArray();
 | 
			
		||||
 | 
			
		||||
        $version = '5.7.33';
 | 
			
		||||
        $current_version = '5.7.35';
 | 
			
		||||
 | 
			
		||||
        $filters = collect($this->version_keys)
 | 
			
		||||
        ->map(function ($value, $key) use ($version, &$version_index, &$index) {
 | 
			
		||||
            if($version == $key) {
 | 
			
		||||
                $version_index = $index;
 | 
			
		||||
            nlog("version = {$version_index}");
 | 
			
		||||
            }
 | 
			
		||||
            $index++;
 | 
			
		||||
            return $value;
 | 
			
		||||
 | 
			
		||||
        })
 | 
			
		||||
        ->slice($version_index ?? 0)
 | 
			
		||||
        ->pluck(Payment::class);
 | 
			
		||||
        
 | 
			
		||||
        $x = collect($p)->diffKeys($filters->filter()->flatten()->flip());
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(5, $filters->count());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private function filterArray($class, array $obj_array)
 | 
			
		||||
    {
 | 
			
		||||
        $index = 0;
 | 
			
		||||
        $version_index = 0;
 | 
			
		||||
 | 
			
		||||
       $filters = collect($this->version_keys)
 | 
			
		||||
            ->map(function ($value, $key) use (&$version_index, &$index) {
 | 
			
		||||
                if($this->import_version == $key) {
 | 
			
		||||
                    $version_index = $index;
 | 
			
		||||
                }
 | 
			
		||||
                                                    
 | 
			
		||||
                $index++;
 | 
			
		||||
                return $value;
 | 
			
		||||
 | 
			
		||||
            })
 | 
			
		||||
            ->when($version_index == 0, function ($collection){
 | 
			
		||||
                return collect([]);
 | 
			
		||||
            })
 | 
			
		||||
            ->when($version_index > 0, function ($collection) use (&$version_index, $class) {
 | 
			
		||||
                return $collection->slice($version_index)->pluck($class)->filter();
 | 
			
		||||
            });
 | 
			
		||||
        
 | 
			
		||||
            return collect($obj_array)->diffKeys($filters->flatten()->flip())->toArray();
 | 
			
		||||
 | 
			
		||||
            // return $filters->count() > 0 ?  collect($obj_array)->diffKeys($filters->flatten()->flip())->toArray() : $obj_array;
 | 
			
		||||
 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testFilterArrayOne()
 | 
			
		||||
    {
 | 
			
		||||
        $u = User::factory()->make()->toArray();
 | 
			
		||||
 | 
			
		||||
        $prop_count = count($u);
 | 
			
		||||
 | 
			
		||||
        $this->import_version = '5.7.42';
 | 
			
		||||
 | 
			
		||||
        $filtered_u = $this->filterArray(User::class, $u);
 | 
			
		||||
 | 
			
		||||
        $this->assertCount($prop_count, $filtered_u);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user