1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-09-20 16:31:33 +02:00

Merge pull request #8478 from turbo124/v5-develop

?with filter query optimization
This commit is contained in:
David Bomba 2023-04-27 16:37:22 +10:00 committed by GitHub
commit 08d0f3655e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 5480 additions and 474 deletions

View File

@ -22,7 +22,7 @@ class InvoiceReminderWasEmailed
{ {
use SerializesModels; use SerializesModels;
public function __construct(public InvoiceInvitation $invitation, public Company $company, public array $event_vars, public int $reminder) public function __construct(public InvoiceInvitation $invitation, public Company $company, public array $event_vars, public string $template)
{ {
} }
} }

View File

@ -18,6 +18,7 @@ use Illuminate\Database\Eloquent\Builder;
*/ */
class ClientFilters extends QueryFilters class ClientFilters extends QueryFilters
{ {
/** /**
* Filter by name. * Filter by name.
* *

View File

@ -293,8 +293,16 @@ abstract class QueryFilters
return $this->builder; return $this->builder;
} }
public function with(string $value): Builder public function with(string $value = ''): Builder
{ {
if (strlen($value) == 0) {
return $this->builder;
}
if($this->with_property == 'id') {
$value = $this->decodePrimaryKey($value);
}
return $this->builder return $this->builder
->orWhere($this->with_property, $value) ->orWhere($this->with_property, $value)
->orderByRaw("{$this->with_property} = ? DESC", [$value]) ->orderByRaw("{$this->with_property} = ? DESC", [$value])

View File

@ -48,48 +48,8 @@ class BankIntegrationController extends BaseController
} }
/** /**
* @OA\Get( * @param BankIntegrationFilters $filters
* path="/api/v1/bank_integrations", * @return Responsec
* operationId="getBankIntegrations",
* tags={"bank_integrations"},
* summary="Gets a list of bank_integrations",
* description="Lists all bank integrations",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(ref="#/components/parameters/index"),
* @OA\Parameter(
* name="rows",
* in="query",
* description="The number of bank integrations to return",
* example="50",
* required=false,
* @OA\Schema(
* type="number",
* format="integer",
* ),
* ),
* @OA\Response(
* response=200,
* description="A list of bank integrations",
* @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\JsonContent(ref="#/components/schemas/BankIntegration"),
* ),
* @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"),
* ),
* )
* @param Request $request
* @return Response|mixed
*/ */
public function index(BankIntegrationFilters $filters) public function index(BankIntegrationFilters $filters)
{ {
@ -105,47 +65,6 @@ class BankIntegrationController extends BaseController
* @param BankIntegration $bank_integration * @param BankIntegration $bank_integration
* @return Response * @return Response
* *
*
* @OA\Get(
* path="/api/v1/bank_integrations/{id}",
* operationId="showBankIntegration",
* tags={"bank_integrations"},
* summary="Shows a bank_integration",
* description="Displays a bank_integration by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The BankIntegration Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the bank_integration object",
* @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\JsonContent(ref="#/components/schemas/BankIntegration"),
* ),
* @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 show(ShowBankIntegrationRequest $request, BankIntegration $bank_integration) public function show(ShowBankIntegrationRequest $request, BankIntegration $bank_integration)
{ {
@ -160,47 +79,6 @@ class BankIntegrationController extends BaseController
* @param BankIntegration $bank_integration * @param BankIntegration $bank_integration
* @return Response * @return Response
* *
*
* @OA\Get(
* path="/api/v1/bank_integrations/{id}/edit",
* operationId="editBankIntegration",
* tags={"bank_integrations"},
* summary="Shows a bank_integration for editing",
* description="Displays a bank_integration by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The BankIntegration Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the bank_integration object",
* @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\JsonContent(ref="#/components/schemas/BankIntegration"),
* ),
* @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 edit(EditBankIntegrationRequest $request, BankIntegration $bank_integration) public function edit(EditBankIntegrationRequest $request, BankIntegration $bank_integration)
{ {
@ -214,48 +92,6 @@ class BankIntegrationController extends BaseController
* @param BankIntegration $bank_integration * @param BankIntegration $bank_integration
* @return Response * @return Response
* *
*
*
* @OA\Put(
* path="/api/v1/bank_integrations/{id}",
* operationId="updateBankIntegration",
* tags={"bank_integrations"},
* summary="Updates a bank_integration",
* description="Handles the updating of a bank_integration by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The BankIntegration Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the bank_integration object",
* @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\JsonContent(ref="#/components/schemas/BankIntegration"),
* ),
* @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 update(UpdateBankIntegrationRequest $request, BankIntegration $bank_integration) public function update(UpdateBankIntegrationRequest $request, BankIntegration $bank_integration)
{ {
@ -271,41 +107,15 @@ class BankIntegrationController extends BaseController
* @param CreateBankIntegrationRequest $request * @param CreateBankIntegrationRequest $request
* @return Response * @return Response
* *
* *
*
* @OA\Get(
* path="/api/v1/bank_integrations/create",
* operationId="getBankIntegrationsCreate",
* tags={"bank_integrations"},
* summary="Gets a new blank bank_integration object",
* description="Returns a blank object with default values",
* @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 blank bank_integration object",
* @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\JsonContent(ref="#/components/schemas/BankIntegration"),
* ),
* @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 create(CreateBankIntegrationRequest $request) public function create(CreateBankIntegrationRequest $request)
{ {
$bank_integration = BankIntegrationFactory::create(auth()->user()->company()->id, auth()->user()->id, auth()->user()->account_id);
/** @var \App\Models\User $user */
$user = auth()->user();
$bank_integration = BankIntegrationFactory::create($user->company()->id, $user->id, $user->account_id);
return $this->itemResponse($bank_integration); return $this->itemResponse($bank_integration);
} }
@ -316,42 +126,15 @@ class BankIntegrationController extends BaseController
* @param StoreBankIntegrationRequest $request * @param StoreBankIntegrationRequest $request
* @return Response * @return Response
* *
*
*
* @OA\Post(
* path="/api/v1/bank_integrations",
* operationId="storeBankIntegration",
* tags={"bank_integrations"},
* summary="Adds a bank_integration",
* description="Adds an bank_integration to a company",
* @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="Returns the saved bank_integration object",
* @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\JsonContent(ref="#/components/schemas/BankIntegration"),
* ),
* @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 store(StoreBankIntegrationRequest $request) public function store(StoreBankIntegrationRequest $request)
{ {
/** @var \App\Models\User $user */
$user = auth()->user();
//stub to store the model //stub to store the model
$bank_integration = $this->bank_integration_repo->save($request->all(), BankIntegrationFactory::create(auth()->user()->company()->id, auth()->user()->id, auth()->user()->account_id)); $bank_integration = $this->bank_integration_repo->save($request->all(), BankIntegrationFactory::create($user->company()->id, $user->id, $user->account_id));
return $this->itemResponse($bank_integration); return $this->itemResponse($bank_integration);
} }
@ -363,47 +146,7 @@ class BankIntegrationController extends BaseController
* @param BankIntegration $bank_integration * @param BankIntegration $bank_integration
* @return Response * @return Response
* *
*
* @throws \Exception * @throws \Exception
* @OA\Delete(
* path="/api/v1/bank_integrations/{id}",
* operationId="deleteBankIntegration",
* tags={"bank_integrations"},
* summary="Deletes a bank_integration",
* description="Handles the deletion of a bank_integration by id",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The BankIntegration Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns a HTTP status",
* @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 destroy(DestroyBankIntegrationRequest $request, BankIntegration $bank_integration) public function destroy(DestroyBankIntegrationRequest $request, BankIntegration $bank_integration)
{ {
@ -418,49 +161,6 @@ class BankIntegrationController extends BaseController
* *
* @return Collection * @return Collection
* *
* @OA\Post(
* path="/api/v1/bank_integrations/bulk",
* operationId="bulkBankIntegrations",
* tags={"bank_integrations"},
* summary="Performs bulk actions on an array of bank_integrations",
* description="",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/index"),
* @OA\RequestBody(
* description="Action paramters",
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="array",
* @OA\Items(
* type="integer",
* description="Array of hashed IDs to be bulk 'actioned",
* example="[0,1,2,3]",
* ),
* )
* )
* ),
* @OA\Response(
* response=200,
* description="The Bulk Action response",
* @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 bulk(BulkBankIntegrationRequest $request) public function bulk(BulkBankIntegrationRequest $request)
{ {
@ -485,43 +185,19 @@ class BankIntegrationController extends BaseController
* Return the remote list of accounts stored on the third party provider. * Return the remote list of accounts stored on the third party provider.
* *
* @return Response * @return Response
*
* @OA\Post(
* path="/api/v1/bank_integrations/refresh_accounts",
* operationId="getRefreshAccounts",
* tags={"bank_integrations"},
* summary="Gets the list of accounts from the remote server",
* description="Adds an bank_integration to a company",
* @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="Returns the saved bank_integration object",
* @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\JsonContent(ref="#/components/schemas/BankIntegration"),
* ),
* @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 refreshAccounts(AdminBankIntegrationRequest $request) public function refreshAccounts(AdminBankIntegrationRequest $request)
{ {
// As yodlee is the first integration we don't need to perform switches yet, however // As yodlee is the first integration we don't need to perform switches yet, however
// if we add additional providers we can reuse this class // if we add additional providers we can reuse this class
$bank_account_id = auth()->user()->account->bank_integration_account_id;
/** @var \App\Models\User $user */
$user = auth()->user();
$user_account = $user->account;
$bank_account_id = $user_account->bank_integration_account_id;
if (!$bank_account_id) { if (!$bank_account_id) {
return response()->json(['message' => 'Not yet authenticated with Bank Integration service'], 400); return response()->json(['message' => 'Not yet authenticated with Bank Integration service'], 400);
@ -532,11 +208,11 @@ class BankIntegrationController extends BaseController
$accounts = $yodlee->getAccounts(); $accounts = $yodlee->getAccounts();
foreach ($accounts as $account) { foreach ($accounts as $account) {
if (!BankIntegration::withTrashed()->where('bank_account_id', $account['id'])->where('company_id', auth()->user()->company()->id)->exists()) { if (!BankIntegration::withTrashed()->where('bank_account_id', $account['id'])->where('company_id', $user->company()->id)->exists()) {
$bank_integration = new BankIntegration(); $bank_integration = new BankIntegration();
$bank_integration->company_id = auth()->user()->company()->id; $bank_integration->company_id = $user->company()->id;
$bank_integration->account_id = auth()->user()->account_id; $bank_integration->account_id = $user->account_id;
$bank_integration->user_id = auth()->user()->id; $bank_integration->user_id = $user->id;
$bank_integration->bank_account_id = $account['id']; $bank_integration->bank_account_id = $account['id'];
$bank_integration->bank_account_type = $account['account_type']; $bank_integration->bank_account_type = $account['account_type'];
$bank_integration->bank_account_name = $account['account_name']; $bank_integration->bank_account_name = $account['account_name'];
@ -550,18 +226,16 @@ class BankIntegrationController extends BaseController
$bank_integration->save(); $bank_integration->save();
} }
} }
$account = auth()->user()->account;
if (Cache::get("throttle_polling:{$account->key}")) { if (Cache::get("throttle_polling:{$account->key}")) {
return response()->json(BankIntegration::query()->company(), 200); return response()->json(BankIntegration::query()->company(), 200);
} }
$account->bank_integrations->each(function ($bank_integration) use ($account) { $user_account->bank_integrations->each(function ($bank_integration) use ($user_account) {
ProcessBankTransactions::dispatch($account->bank_integration_account_id, $bank_integration); ProcessBankTransactions::dispatch($user_account->bank_integration_account_id, $bank_integration);
}); });
Cache::put("throttle_polling:{$account->key}", true, 300); Cache::put("throttle_polling:{$user_account->key}", true, 300);
return response()->json(BankIntegration::query()->company(), 200); return response()->json(BankIntegration::query()->company(), 200);
} }
@ -572,40 +246,16 @@ class BankIntegrationController extends BaseController
* *
* @return Response * @return Response
* *
* @OA\Post(
* path="/api/v1/bank_integrations/remove_account/account_id",
* operationId="getRemoveAccount",
* tags={"bank_integrations"},
* summary="Removes an account from the integration",
* description="Removes an account from the integration",
* @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="Returns the bank_integration object",
* @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\JsonContent(ref="#/components/schemas/BankIntegration"),
* ),
* @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 removeAccount(AdminBankIntegrationRequest $request, $acc_id) public function removeAccount(AdminBankIntegrationRequest $request, $acc_id)
{ {
$bank_account_id = auth()->user()->account->bank_integration_account_id; /** @var \App\Models\User $user */
$user = auth()->user();
$account = $user->account;
$bank_account_id = $account->bank_integration_account_id;
if (!$bank_account_id) { if (!$bank_account_id) {
return response()->json(['message' => 'Not yet authenticated with Bank Integration service'], 400); return response()->json(['message' => 'Not yet authenticated with Bank Integration service'], 400);
@ -628,40 +278,14 @@ class BankIntegrationController extends BaseController
* *
* @return Response * @return Response
* *
* @OA\Post(
* path="/api/v1/bank_integrations/get_transactions/account_id",
* operationId="getAccountTransactions",
* tags={"bank_integrations"},
* summary="Retrieve transactions for a account",
* description="Retrieve transactions for a account",
* @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="Retrieve transactions for a account",
* @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\JsonContent(ref="#/components/schemas/BankIntegration"),
* ),
* @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 getTransactions(AdminBankIntegrationRequest $request) public function getTransactions(AdminBankIntegrationRequest $request)
{ {
auth()->user()->account->bank_integrations->each(function ($bank_integration) { /** @var \App\Models\User $user */
(new ProcessBankTransactions(auth()->user()->account->bank_integration_account_id, $bank_integration))->handle(); $user = auth()->user();
$user->account->bank_integrations->each(function ($bank_integration) use ($user){
(new ProcessBankTransactions($user->account->bank_integration_account_id, $bank_integration))->handle();
}); });
return response()->json(['message' => 'Fetching transactions....'], 200); return response()->json(['message' => 'Fetching transactions....'], 200);

View File

@ -136,7 +136,10 @@ class EmailController extends BaseController
$mo->email_template_body = $request->input('template'); $mo->email_template_body = $request->input('template');
$mo->email_template_subject = str_replace("template", "subject", $request->input('template')); $mo->email_template_subject = str_replace("template", "subject", $request->input('template'));
if ($request->has('cc_email') && $request->cc_email) { /** @var \App\Models\User $user */
$user = auth()->user();
if ($request->has('cc_email') && $request->cc_email && (Ninja::isSelfHost() || $user->account->isPaidHostedClient())) {
$mo->cc[] = new Address($request->cc_email); $mo->cc[] = new Address($request->cc_email);
} }
@ -144,8 +147,6 @@ class EmailController extends BaseController
if (! $invitation->contact->trashed() && $invitation->contact->email) { if (! $invitation->contact->trashed() && $invitation->contact->email) {
$entity_obj->service()->markSent()->save(); $entity_obj->service()->markSent()->save();
// EmailEntity::dispatch($invitation->fresh(), $invitation->company, $template, $data);
$mo->invitation_id = $invitation->id; $mo->invitation_id = $invitation->id;
Email::dispatch($mo, $invitation->company); Email::dispatch($mo, $invitation->company);

View File

@ -92,7 +92,11 @@ class SendEmailRequest extends Request
/*Make sure we have all the require ingredients to send a template*/ /*Make sure we have all the require ingredients to send a template*/
if (array_key_exists('entity', $input) && array_key_exists('entity_id', $input) && is_string($input['entity']) && $input['entity_id']) { if (array_key_exists('entity', $input) && array_key_exists('entity_id', $input) && is_string($input['entity']) && $input['entity_id']) {
$company = auth()->user()->company();
/** @var \App\Models\User $user */
$user = auth()->user();
$company = $user->company();
$entity = $input['entity']; $entity = $input['entity'];
@ -100,7 +104,7 @@ class SendEmailRequest extends Request
$entity_obj = $entity::whereId($input['entity_id'])->withTrashed()->company()->first(); $entity_obj = $entity::whereId($input['entity_id'])->withTrashed()->company()->first();
/* Check object, check user and company id is same as users, and check user can edit the object */ /* Check object, check user and company id is same as users, and check user can edit the object */
if ($entity_obj && ($company->id == $entity_obj->company_id) && auth()->user()->can('edit', $entity_obj)) { if ($entity_obj && ($company->id == $entity_obj->company_id) && $user->can('edit', $entity_obj)) {
return true; return true;
} }
} }

View File

@ -37,6 +37,8 @@ class InvoiceEmailedNotification implements ShouldQueue
*/ */
public function handle($event) public function handle($event)
{ {
nlog($event->template);
MultiDB::setDb($event->company->db); MultiDB::setDb($event->company->db);
$first_notification_sent = true; $first_notification_sent = true;
@ -61,6 +63,20 @@ class InvoiceEmailedNotification implements ShouldQueue
if (($key = array_search('mail', $methods)) !== false) { if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]); unset($methods[$key]);
// $template = $event->template ?? '';
// if(isset($event->reminder)){
// $template = match($event->reminder){
// 63 => 'reminder1',
// 64 => 'reminder2',
// 65 => 'reminder3',
// 66 => 'endless_reminder',
// default => ''
// };
// }
$nmo = new NinjaMailerObject; $nmo = new NinjaMailerObject;
$nmo->mailable = new NinjaMailer((new EntitySentObject($event->invitation, 'invoice', $event->template))->build()); $nmo->mailable = new NinjaMailer((new EntitySentObject($event->invitation, 'invoice', $event->template))->build());
$nmo->company = $invoice->company; $nmo->company = $invoice->company;

View File

@ -136,6 +136,12 @@ class EntitySentObject
$this->template_subject = 'texts.notification_purchase_order_sent_subject'; $this->template_subject = 'texts.notification_purchase_order_sent_subject';
$this->template_body = 'texts.notification_purchase_order_sent'; $this->template_body = 'texts.notification_purchase_order_sent';
break; break;
case 'custom1':
case 'custom2':
case 'custom3':
$this->template_subject = 'texts.notification_invoice_custom_sent_subject';
$this->template_body = 'texts.notification_invoice_sent';
break;
default: default:
$this->template_subject = 'texts.notification_invoice_sent_subject'; $this->template_subject = 'texts.notification_invoice_sent_subject';
$this->template_body = 'texts.notification_invoice_sent'; $this->template_body = 'texts.notification_invoice_sent';

View File

@ -38,7 +38,8 @@ use Illuminate\Support\Str;
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel exclude(array $excludeable) * @method static \Illuminate\Database\Eloquent\Builder|BaseModel exclude(array $excludeable)
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel withTrashed() * @method static \Illuminate\Database\Eloquent\Builder|BaseModel withTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel scopeExclude() * @method static \Illuminate\Database\Eloquent\Builder|BaseModel scopeExclude()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel find() * @method static \Illuminate\Database\Eloquent\Builder|BaseModel find()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel whereIn()
* @method \App\Models\Company company() * @method \App\Models\Company company()
* @method int companyId() * @method int companyId()
* @method Builder|static exclude($columns) * @method Builder|static exclude($columns)

View File

@ -801,22 +801,29 @@ class Invoice extends BaseModel
public function entityEmailEvent($invitation, $reminder_template, $template = '') public function entityEmailEvent($invitation, $reminder_template, $template = '')
{ {
nlog($template);
switch ($reminder_template) { switch ($reminder_template) {
case 'invoice': case 'invoice':
event(new InvoiceWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template)); event(new InvoiceWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
break; break;
case 'reminder1': case 'reminder1':
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), Activity::INVOICE_REMINDER1_SENT)); event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
break; break;
case 'reminder2': case 'reminder2':
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), Activity::INVOICE_REMINDER2_SENT)); event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
break; break;
case 'reminder3': case 'reminder3':
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), Activity::INVOICE_REMINDER3_SENT)); event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
break; break;
case 'reminder_endless': case 'reminder_endless':
case 'endless_reminder': case 'endless_reminder':
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), Activity::INVOICE_REMINDER_ENDLESS_SENT)); event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
break;
case 'custom1':
case 'custom2':
case 'custom3':
event(new InvoiceReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $template));
break; break;
default: default:
// code... // code...

View File

@ -25,6 +25,8 @@ use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundExceptio
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|StaticModel newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel newQuery() * @method static \Illuminate\Database\Eloquent\Builder|StaticModel newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel query() * @method static \Illuminate\Database\Eloquent\Builder|StaticModel query()
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel find()
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel findOrFail()
* @mixin \Eloquent * @mixin \Eloquent
*/ */
class StaticModel extends Model class StaticModel extends Model
@ -50,7 +52,10 @@ class StaticModel extends Model
*/ */
public function scopeCompany($query) public function scopeCompany($query)
{ {
$query->where('company_id', auth()->user()->companyId()); /** @var \App\Models\User $user */
$user = auth()->user();
$query->where('company_id', $user->companyId());
return $query; return $query;
} }

View File

@ -40,15 +40,15 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function boot() public function boot()
{ {
// DB::listen(function($query) { \DB::listen(function($query) {
// nlog( nlog(
// $query->sql, $query->sql,
// [ [
// 'bindings' => $query->bindings, 'bindings' => $query->bindings,
// 'time' => $query->time 'time' => $query->time
// ] ]
// ); );
// }); });
// Model::preventLazyLoading( // Model::preventLazyLoading(
// !$this->app->isProduction() // !$this->app->isProduction()

View File

@ -0,0 +1,37 @@
<?php
use App\Models\Language;
use Illuminate\Database\Migrations\Migration;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Language::unguard();
$language = Language::find(38);
if (! $language) {
Language::create(['id' => 38, 'name' => 'Khmer', 'locale' => 'km_KH']);
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
};

View File

@ -57,6 +57,12 @@ class LanguageSeeder extends Seeder
['id' => 30, 'name' => 'Arabic', 'locale' => 'ar'], ['id' => 30, 'name' => 'Arabic', 'locale' => 'ar'],
['id' => 31, 'name' => 'Persian', 'locale' => 'fa'], ['id' => 31, 'name' => 'Persian', 'locale' => 'fa'],
['id' => 32, 'name' => 'Latvian', 'locale' => 'lv_LV'], ['id' => 32, 'name' => 'Latvian', 'locale' => 'lv_LV'],
['id' => 33, 'name' => 'Serbian', 'locale' => 'sr'],
['id' => 34, 'name' => 'Slovak', 'locale' => 'sk'],
['id' => 35, 'name' => 'Estonian', 'locale' => 'et'],
['id' => 36, 'name' => 'Bulgarian', 'locale' => 'bg'],
['id' => 37, 'name' => 'Hebrew', 'locale' => 'he'],
['id' => 38, 'name' => 'Khmer', 'locale' => 'km_KH'],
]; ];
foreach ($languages as $language) { foreach ($languages as $language) {
@ -69,29 +75,5 @@ class LanguageSeeder extends Seeder
} }
} }
if (!Language::find(33)) {
$serbian = ['id' => 33, 'name' => 'Serbian', 'locale' => 'sr'];
Language::create($serbian);
}
if (!Language::find(34)) {
$slovak = ['id' => 34, 'name' => 'Slovak', 'locale' => 'sk'];
Language::create($slovak);
}
if (!Language::find(35)) {
$estonia = ['id' => 35, 'name' => 'Estonian', 'locale' => 'et'];
Language::create($estonia);
}
if (!Language::find(36)) {
$bulgarian = ['id' => 36, 'name' => 'Bulgarian', 'locale' => 'bg'];
Language::create($bulgarian);
}
if (!Language::find(37)) {
$hebrew = ['id' => 37, 'name' => 'Hebrew', 'locale' => 'he'];
Language::create($hebrew);
}
} }
} }

View File

@ -5002,7 +5002,7 @@ $LANG = array(
'payment_type_Interac E Transfer' => 'Interac E Transfer', 'payment_type_Interac E Transfer' => 'Interac E Transfer',
'xinvoice_payable' => 'مستحق الدفع paydate: صافي أيام الدفع payeddue: تاريخ الدفع', 'xinvoice_payable' => 'مستحق الدفع paydate: صافي أيام الدفع payeddue: تاريخ الدفع',
'xinvoice_no_buyers_reference' => "لم يتم إعطاء إشارة للمشتري", 'xinvoice_no_buyers_reference' => "لم يتم إعطاء إشارة للمشتري",
'xinvoice_online_payment' => 'يجب دفع الفاتورة عبر الإنترنت من خلال الرابط المقدم', 'xinvoice_online_payment' => 'The invoice needs to be paid online via the provided link',
'pre_payment' => 'الدفع المسبق', 'pre_payment' => 'الدفع المسبق',
'number_of_payments' => 'عدد الدفعات', 'number_of_payments' => 'عدد الدفعات',
'number_of_payments_helper' => 'عدد المرات التي سيتم فيها إجراء هذه الدفعة', 'number_of_payments_helper' => 'عدد المرات التي سيتم فيها إجراء هذه الدفعة',
@ -5086,6 +5086,8 @@ $LANG = array(
'services' => 'Services', 'services' => 'Services',
'shipping' => 'Shipping', 'shipping' => 'Shipping',
'tax_exempt' => 'Tax Exempt', 'tax_exempt' => 'Tax Exempt',
'late_fee_added_locked_invoice' => 'Late fee for invoice :invoice added on :date',
); );

View File

@ -4983,7 +4983,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
'payment_type_Interac E Transfer' => 'Interac E-Übertragung', 'payment_type_Interac E Transfer' => 'Interac E-Übertragung',
'xinvoice_payable' => 'Zahlbar innerhalb von :payeddue Tagen netto bis :paydate', 'xinvoice_payable' => 'Zahlbar innerhalb von :payeddue Tagen netto bis :paydate',
'xinvoice_no_buyers_reference' => "Keine Käuferreferenz angegeben", 'xinvoice_no_buyers_reference' => "Keine Käuferreferenz angegeben",
'xinvoice_online_payment' => 'Die Rechnung muss online über den bereitgestellten Link bezahlt werden', 'xinvoice_online_payment' => 'The invoice needs to be paid online via the provided link',
'pre_payment' => 'Vorauszahlung', 'pre_payment' => 'Vorauszahlung',
'number_of_payments' => 'Anzahl der Zahlungen', 'number_of_payments' => 'Anzahl der Zahlungen',
'number_of_payments_helper' => 'Die Häufigkeit, mit der diese Zahlung erfolgt', 'number_of_payments_helper' => 'Die Häufigkeit, mit der diese Zahlung erfolgt',
@ -5067,6 +5067,8 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting',
'services' => 'Services', 'services' => 'Services',
'shipping' => 'Shipping', 'shipping' => 'Shipping',
'tax_exempt' => 'Tax Exempt', 'tax_exempt' => 'Tax Exempt',
'late_fee_added_locked_invoice' => 'Late fee for invoice :invoice added on :date',
); );

View File

@ -4012,6 +4012,7 @@ $LANG = array(
'notification_invoice_reminder1_sent_subject' => 'Reminder 1 for Invoice :invoice was sent to :client', 'notification_invoice_reminder1_sent_subject' => 'Reminder 1 for Invoice :invoice was sent to :client',
'notification_invoice_reminder2_sent_subject' => 'Reminder 2 for Invoice :invoice was sent to :client', 'notification_invoice_reminder2_sent_subject' => 'Reminder 2 for Invoice :invoice was sent to :client',
'notification_invoice_reminder3_sent_subject' => 'Reminder 3 for Invoice :invoice was sent to :client', 'notification_invoice_reminder3_sent_subject' => 'Reminder 3 for Invoice :invoice was sent to :client',
'notification_invoice_custom_sent_subject' => 'Custom reminder for Invoice :invoice was sent to :client',
'notification_invoice_reminder_endless_sent_subject' => 'Endless reminder for Invoice :invoice was sent to :client', 'notification_invoice_reminder_endless_sent_subject' => 'Endless reminder for Invoice :invoice was sent to :client',
'assigned_user' => 'Assigned User', 'assigned_user' => 'Assigned User',
'setup_steps_notice' => 'To proceed to next step, make sure you test each section.', 'setup_steps_notice' => 'To proceed to next step, make sure you test each section.',
@ -5066,7 +5067,7 @@ $LANG = array(
'shipping' => 'Shipping', 'shipping' => 'Shipping',
'tax_exempt' => 'Tax Exempt', 'tax_exempt' => 'Tax Exempt',
'late_fee_added_locked_invoice' => 'Late fee for invoice :invoice added on :date', 'late_fee_added_locked_invoice' => 'Late fee for invoice :invoice added on :date',
'lang_Khmer' => 'Khmer',
); );

View File

@ -4979,7 +4979,7 @@ $LANG = array(
'payment_type_Interac E Transfer' => 'Transferencia Interac E', 'payment_type_Interac E Transfer' => 'Transferencia Interac E',
'xinvoice_payable' => 'Payable within :payeddue days net until :paydate', 'xinvoice_payable' => 'Payable within :payeddue days net until :paydate',
'xinvoice_no_buyers_reference' => "No se da referencia del comprador", 'xinvoice_no_buyers_reference' => "No se da referencia del comprador",
'xinvoice_online_payment' => 'La factura debe pagarse en línea a través del enlace provisto', 'xinvoice_online_payment' => 'The invoice needs to be paid online via the provided link',
'pre_payment' => 'Prepago', 'pre_payment' => 'Prepago',
'number_of_payments' => 'numero de pagos', 'number_of_payments' => 'numero de pagos',
'number_of_payments_helper' => 'El número de veces que se realizará este pago.', 'number_of_payments_helper' => 'El número de veces que se realizará este pago.',
@ -5063,6 +5063,8 @@ $LANG = array(
'services' => 'Services', 'services' => 'Services',
'shipping' => 'Shipping', 'shipping' => 'Shipping',
'tax_exempt' => 'Tax Exempt', 'tax_exempt' => 'Tax Exempt',
'late_fee_added_locked_invoice' => 'Late fee for invoice :invoice added on :date',
); );

View File

@ -4971,7 +4971,7 @@ Una vez que tenga los montos, vuelva a esta página de métodos de pago y haga c
'payment_type_Interac E Transfer' => 'Interac E Transfer', 'payment_type_Interac E Transfer' => 'Interac E Transfer',
'xinvoice_payable' => 'Pagadero dentro de :payeddue días de pago vencido neto hasta :paydate', 'xinvoice_payable' => 'Pagadero dentro de :payeddue días de pago vencido neto hasta :paydate',
'xinvoice_no_buyers_reference' => "No se da la referencia del comprador", 'xinvoice_no_buyers_reference' => "No se da la referencia del comprador",
'xinvoice_online_payment' => 'La factura debe pagarse en línea a través del enlace proporcionado.', 'xinvoice_online_payment' => 'The invoice needs to be paid online via the provided link',
'pre_payment' => 'Prepago', 'pre_payment' => 'Prepago',
'number_of_payments' => 'Numero de pagos', 'number_of_payments' => 'Numero de pagos',
'number_of_payments_helper' => 'El número de veces que se realizará este pago.', 'number_of_payments_helper' => 'El número de veces que se realizará este pago.',
@ -5055,6 +5055,8 @@ Una vez que tenga los montos, vuelva a esta página de métodos de pago y haga c
'services' => 'Servicios', 'services' => 'Servicios',
'shipping' => 'Envío', 'shipping' => 'Envío',
'tax_exempt' => 'Exento de impuestos', 'tax_exempt' => 'Exento de impuestos',
'late_fee_added_locked_invoice' => 'Late fee for invoice :invoice added on :date',
); );

View File

@ -4975,7 +4975,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'payment_type_Interac E Transfer' => 'Virement Interac E', 'payment_type_Interac E Transfer' => 'Virement Interac E',
'xinvoice_payable' => 'Payable sous :payeddue days net jusqu\'au :paydate', 'xinvoice_payable' => 'Payable sous :payeddue days net jusqu\'au :paydate',
'xinvoice_no_buyers_reference' => "Aucune référence d'acheteur donnée", 'xinvoice_no_buyers_reference' => "Aucune référence d'acheteur donnée",
'xinvoice_online_payment' => 'La facture doit être payée en ligne via le lien fourni', 'xinvoice_online_payment' => 'The invoice needs to be paid online via the provided link',
'pre_payment' => 'Prépaiement', 'pre_payment' => 'Prépaiement',
'number_of_payments' => 'Nombre de paiements', 'number_of_payments' => 'Nombre de paiements',
'number_of_payments_helper' => 'Le nombre de fois que ce paiement sera effectué', 'number_of_payments_helper' => 'Le nombre de fois que ce paiement sera effectué',
@ -5059,6 +5059,8 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'services' => 'Services', 'services' => 'Services',
'shipping' => 'Shipping', 'shipping' => 'Shipping',
'tax_exempt' => 'Tax Exempt', 'tax_exempt' => 'Tax Exempt',
'late_fee_added_locked_invoice' => 'Late fee for invoice :invoice added on :date',
); );

View File

@ -4882,7 +4882,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'email_queued' => 'Courriel en file d\'attente', 'email_queued' => 'Courriel en file d\'attente',
'clone_to_recurring_invoice' => 'Dupliquer en facture récurrente', 'clone_to_recurring_invoice' => 'Dupliquer en facture récurrente',
'inventory_threshold' => 'Seuil d\'inventaire', 'inventory_threshold' => 'Seuil d\'inventaire',
'emailed_statement' => 'L\'état de compte a été mis en file d\'attente pour l\'envoi', 'emailed_statement' => 'Le relevé a été mis en file d\'attente pour l\'envoi',
'show_email_footer' => 'Afficher le pied de page du courriel', 'show_email_footer' => 'Afficher le pied de page du courriel',
'invoice_task_hours' => 'Facturer les heures de tâches', 'invoice_task_hours' => 'Facturer les heures de tâches',
'invoice_task_hours_help' => 'Ajouter ces heures aux articles de la facture', 'invoice_task_hours_help' => 'Ajouter ces heures aux articles de la facture',
@ -4910,7 +4910,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'all_clients' => 'Tous les clients', 'all_clients' => 'Tous les clients',
'show_aging_table' => 'Afficher la liste des impayés', 'show_aging_table' => 'Afficher la liste des impayés',
'show_payments_table' => 'Afficher la liste des paiements', 'show_payments_table' => 'Afficher la liste des paiements',
'email_statement' => 'Envoyer par courriel l\'état de compte', 'email_statement' => 'Envoyer le relevé par courriel',
'once' => 'Une fois', 'once' => 'Une fois',
'schedules' => 'Planifications', 'schedules' => 'Planifications',
'new_schedule' => 'Nouvelle planification', 'new_schedule' => 'Nouvelle planification',
@ -4973,7 +4973,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'payment_type_Interac E Transfer' => 'Transfert Interac', 'payment_type_Interac E Transfer' => 'Transfert Interac',
'xinvoice_payable' => 'Payable d\'ici :payeddue jours jusqu\'à :paydate', 'xinvoice_payable' => 'Payable d\'ici :payeddue jours jusqu\'à :paydate',
'xinvoice_no_buyers_reference' => "Aucune référence de l'acheteur fournie", 'xinvoice_no_buyers_reference' => "Aucune référence de l'acheteur fournie",
'xinvoice_online_payment' => 'Cette facture doit être payée en ligne en utilisant le lien fourni', 'xinvoice_online_payment' => 'Cette facture doit être payée en ligne en suivant le lien fourni',
'pre_payment' => 'Prépaiement', 'pre_payment' => 'Prépaiement',
'number_of_payments' => 'Nombre de paiements', 'number_of_payments' => 'Nombre de paiements',
'number_of_payments_helper' => 'Nombre de fois que ce paiement sera fait', 'number_of_payments_helper' => 'Nombre de fois que ce paiement sera fait',
@ -5037,7 +5037,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'tax_all' => 'Tout taxer', 'tax_all' => 'Tout taxer',
'tax_selected' => 'Taxe sélectionnée', 'tax_selected' => 'Taxe sélectionnée',
'version' => 'version', 'version' => 'version',
'seller_subregion' => 'Sous-région du vendeur', 'seller_subregion' => 'Province du vendeur',
'calculate_taxes' => 'Calculer les taxes', 'calculate_taxes' => 'Calculer les taxes',
'calculate_taxes_help' => 'Calcul automatique des taxes à la sauvegarde des factures', 'calculate_taxes_help' => 'Calcul automatique des taxes à la sauvegarde des factures',
'link_expenses' => 'Lier les dépenses', 'link_expenses' => 'Lier les dépenses',
@ -5057,6 +5057,8 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'services' => 'Services', 'services' => 'Services',
'shipping' => 'Livraison', 'shipping' => 'Livraison',
'tax_exempt' => 'Exemption de taxes', 'tax_exempt' => 'Exemption de taxes',
'late_fee_added_locked_invoice' => 'Les frais de retard pour la facture :invoice ont été ajoutés le :date',
); );

View File

@ -4966,7 +4966,7 @@ $LANG = array(
'payment_type_Interac E Transfer' => 'Interac E Trasferimento', 'payment_type_Interac E Transfer' => 'Interac E Trasferimento',
'xinvoice_payable' => 'Pagabile entro :payeddue giorni netti fino :paydate', 'xinvoice_payable' => 'Pagabile entro :payeddue giorni netti fino :paydate',
'xinvoice_no_buyers_reference' => "Nessun riferimento dell&#39;acquirente fornito", 'xinvoice_no_buyers_reference' => "Nessun riferimento dell&#39;acquirente fornito",
'xinvoice_online_payment' => 'La fattura deve essere pagata online tramite il link fornito', 'xinvoice_online_payment' => 'The invoice needs to be paid online via the provided link',
'pre_payment' => 'Pagamento anticipato', 'pre_payment' => 'Pagamento anticipato',
'number_of_payments' => 'Numero di pagamenti', 'number_of_payments' => 'Numero di pagamenti',
'number_of_payments_helper' => 'Il numero di volte in cui verrà effettuato questo pagamento', 'number_of_payments_helper' => 'Il numero di volte in cui verrà effettuato questo pagamento',
@ -5050,6 +5050,8 @@ $LANG = array(
'services' => 'Services', 'services' => 'Services',
'shipping' => 'Shipping', 'shipping' => 'Shipping',
'tax_exempt' => 'Tax Exempt', 'tax_exempt' => 'Tax Exempt',
'late_fee_added_locked_invoice' => 'Late fee for invoice :invoice added on :date',
); );

20
lang/km_KH/auth.php Normal file
View File

@ -0,0 +1,20 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'failed' => 'These credentials do not match our records.',
'password' => 'The provided password is incorrect.',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
];

13
lang/km_KH/help.php Normal file
View File

@ -0,0 +1,13 @@
<?php
$lang = [
'client_dashboard' => 'Message to be displayed on clients dashboard',
'client_currency' => 'The client currency.',
'client_language' => 'The client language.',
'client_payment_terms' => 'The client payment terms.',
'client_paid_invoice' => 'Message to be displayed on a clients paid invoice screen',
'client_unpaid_invoice' => 'Message to be displayed on a clients unpaid invoice screen',
'client_unapproved_quote' => 'Message to be displayed on a clients unapproved quote screen',
];
return $lang;

19
lang/km_KH/pagination.php Normal file
View File

@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Pagination Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the simple pagination links. You are free to change them to anything
| you want to customize your views to better match your application.
|
*/
'previous' => '« Previous',
'next' => 'Next »',
];

23
lang/km_KH/passwords.php Normal file
View File

@ -0,0 +1,23 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Password Reset Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
'password' => 'Passwords must be at least six characters and match the confirmation.',
'reset' => 'Your password has been reset!',
'sent' => 'We have e-mailed your password reset link!',
'token' => 'This password reset token is invalid.',
'user' => "We can't find a user with that e-mail address.",
'throttled' => 'You have requested password reset recently, please check your email.',
];

5048
lang/km_KH/texts.php Normal file

File diff suppressed because it is too large Load Diff

170
lang/km_KH/validation.php Normal file
View File

@ -0,0 +1,170 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'accepted' => 'The :attribute must be accepted.',
'accepted_if' => 'The :attribute must be accepted when :other is :value.',
'active_url' => 'The :attribute is not a valid URL.',
'after' => 'The :attribute must be a date after :date.',
'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
'alpha' => 'The :attribute must only contain letters.',
'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.',
'alpha_num' => 'The :attribute must only contain letters and numbers.',
'array' => 'The :attribute must be an array.',
'before' => 'The :attribute must be a date before :date.',
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
'between' => [
'array' => 'The :attribute must have between :min and :max items.',
'file' => 'The :attribute must be between :min and :max kilobytes.',
'numeric' => 'The :attribute must be between :min and :max.',
'string' => 'The :attribute must be between :min and :max characters.',
],
'boolean' => 'The :attribute field must be true or false.',
'confirmed' => 'The :attribute confirmation does not match.',
'current_password' => 'The password is incorrect.',
'date' => 'The :attribute is not a valid date.',
'date_equals' => 'The :attribute must be a date equal to :date.',
'date_format' => 'The :attribute does not match the format :format.',
'declined' => 'The :attribute must be declined.',
'declined_if' => 'The :attribute must be declined when :other is :value.',
'different' => 'The :attribute and :other must be different.',
'digits' => 'The :attribute must be :digits digits.',
'digits_between' => 'The :attribute must be between :min and :max digits.',
'dimensions' => 'The :attribute has invalid image dimensions.',
'distinct' => 'The :attribute field has a duplicate value.',
'email' => 'The :attribute must be a valid email address.',
'ends_with' => 'The :attribute must end with one of the following: :values.',
'enum' => 'The selected :attribute is invalid.',
'exists' => 'The selected :attribute is invalid.',
'file' => 'The :attribute must be a file.',
'filled' => 'The :attribute field must have a value.',
'gt' => [
'array' => 'The :attribute must have more than :value items.',
'file' => 'The :attribute must be greater than :value kilobytes.',
'numeric' => 'The :attribute must be greater than :value.',
'string' => 'The :attribute must be greater than :value characters.',
],
'gte' => [
'array' => 'The :attribute must have :value items or more.',
'file' => 'The :attribute must be greater than or equal to :value kilobytes.',
'numeric' => 'The :attribute must be greater than or equal to :value.',
'string' => 'The :attribute must be greater than or equal to :value characters.',
],
'image' => 'The :attribute must be an image.',
'in' => 'The selected :attribute is invalid.',
'in_array' => 'The :attribute field does not exist in :other.',
'integer' => 'The :attribute must be an integer.',
'ip' => 'The :attribute must be a valid IP address.',
'ipv4' => 'The :attribute must be a valid IPv4 address.',
'ipv6' => 'The :attribute must be a valid IPv6 address.',
'json' => 'The :attribute must be a valid JSON string.',
'lt' => [
'array' => 'The :attribute must have less than :value items.',
'file' => 'The :attribute must be less than :value kilobytes.',
'numeric' => 'The :attribute must be less than :value.',
'string' => 'The :attribute must be less than :value characters.',
],
'lte' => [
'array' => 'The :attribute must not have more than :value items.',
'file' => 'The :attribute must be less than or equal to :value kilobytes.',
'numeric' => 'The :attribute must be less than or equal to :value.',
'string' => 'The :attribute must be less than or equal to :value characters.',
],
'mac_address' => 'The :attribute must be a valid MAC address.',
'max' => [
'array' => 'The :attribute must not have more than :max items.',
'file' => 'The :attribute must not be greater than :max kilobytes.',
'numeric' => 'The :attribute must not be greater than :max.',
'string' => 'The :attribute must not be greater than :max characters.',
],
'mimes' => 'The :attribute must be a file of type: :values.',
'mimetypes' => 'The :attribute must be a file of type: :values.',
'min' => [
'array' => 'The :attribute must have at least :min items.',
'file' => 'The :attribute must be at least :min kilobytes.',
'numeric' => 'The :attribute must be at least :min.',
'string' => 'The :attribute must be at least :min characters.',
],
'multiple_of' => 'The :attribute must be a multiple of :value.',
'not_in' => 'The selected :attribute is invalid.',
'not_regex' => 'The :attribute format is invalid.',
'numeric' => 'The :attribute must be a number.',
'password' => [
'letters' => 'The :attribute must contain at least one letter.',
'mixed' => 'The :attribute must contain at least one uppercase and one lowercase letter.',
'numbers' => 'The :attribute must contain at least one number.',
'symbols' => 'The :attribute must contain at least one symbol.',
'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',
],
'present' => 'The :attribute field must be present.',
'prohibited' => 'The :attribute field is prohibited.',
'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',
'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',
'prohibits' => 'The :attribute field prohibits :other from being present.',
'regex' => 'The :attribute format is invalid.',
'required' => 'The :attribute field is required.',
'required_array_keys' => 'The :attribute field must contain entries for: :values.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values are present.',
'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.',
'same' => 'The :attribute and :other must match.',
'size' => [
'array' => 'The :attribute must contain :size items.',
'file' => 'The :attribute must be :size kilobytes.',
'numeric' => 'The :attribute must be :size.',
'string' => 'The :attribute must be :size characters.',
],
'starts_with' => 'The :attribute must start with one of the following: :values.',
'doesnt_start_with' => 'The :attribute may not start with one of the following: :values.',
'string' => 'The :attribute must be a string.',
'timezone' => 'The :attribute must be a valid timezone.',
'unique' => 'The :attribute has already been taken.',
'uploaded' => 'The :attribute failed to upload.',
'url' => 'The :attribute must be a valid URL.',
'uuid' => 'The :attribute must be a valid UUID.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap our attribute placeholder
| with something more reader friendly such as "E-Mail Address" instead
| of "email". This simply helps us make our message more expressive.
|
*/
'attributes' => [],
];

View File

@ -4975,7 +4975,7 @@ Email: :email<b><br><b>',
'payment_type_Interac E Transfer' => 'Interac E-overdracht', 'payment_type_Interac E Transfer' => 'Interac E-overdracht',
'xinvoice_payable' => 'Te betalen binnen :payeddue vervaldagen netto tot :paydate', 'xinvoice_payable' => 'Te betalen binnen :payeddue vervaldagen netto tot :paydate',
'xinvoice_no_buyers_reference' => "Geen kopersreferentie opgegeven", 'xinvoice_no_buyers_reference' => "Geen kopersreferentie opgegeven",
'xinvoice_online_payment' => 'De factuur dient online betaald te worden via de voorziene link', 'xinvoice_online_payment' => 'The invoice needs to be paid online via the provided link',
'pre_payment' => 'Vooruitbetaling', 'pre_payment' => 'Vooruitbetaling',
'number_of_payments' => 'Aantal betalingen', 'number_of_payments' => 'Aantal betalingen',
'number_of_payments_helper' => 'Het aantal keren dat deze betaling zal worden gedaan', 'number_of_payments_helper' => 'Het aantal keren dat deze betaling zal worden gedaan',
@ -5059,6 +5059,8 @@ Email: :email<b><br><b>',
'services' => 'Diensten', 'services' => 'Diensten',
'shipping' => 'Verzenden', 'shipping' => 'Verzenden',
'tax_exempt' => 'Vrijgesteld van belasting', 'tax_exempt' => 'Vrijgesteld van belasting',
'late_fee_added_locked_invoice' => 'Late fee for invoice :invoice added on :date',
); );

View File

@ -4978,7 +4978,7 @@ O envio de E-mails foi suspenso. Será retomado às 23:00 UTC.',
'payment_type_Interac E Transfer' => 'Interac E Transfer', 'payment_type_Interac E Transfer' => 'Interac E Transfer',
'xinvoice_payable' => 'Pagável dentro de :payeddue dias líquidos até :paydate', 'xinvoice_payable' => 'Pagável dentro de :payeddue dias líquidos até :paydate',
'xinvoice_no_buyers_reference' => "Nenhuma referência do comprador fornecida", 'xinvoice_no_buyers_reference' => "Nenhuma referência do comprador fornecida",
'xinvoice_online_payment' => 'A fatura deve ser paga online através do link fornecido', 'xinvoice_online_payment' => 'The invoice needs to be paid online via the provided link',
'pre_payment' => 'Pré-Pagamento', 'pre_payment' => 'Pré-Pagamento',
'number_of_payments' => 'Número de pagamentos', 'number_of_payments' => 'Número de pagamentos',
'number_of_payments_helper' => 'O número de vezes que esse pagamento será feito', 'number_of_payments_helper' => 'O número de vezes que esse pagamento será feito',
@ -5062,6 +5062,8 @@ O envio de E-mails foi suspenso. Será retomado às 23:00 UTC.',
'services' => 'Services', 'services' => 'Services',
'shipping' => 'Shipping', 'shipping' => 'Shipping',
'tax_exempt' => 'Tax Exempt', 'tax_exempt' => 'Tax Exempt',
'late_fee_added_locked_invoice' => 'Late fee for invoice :invoice added on :date',
); );

View File

@ -4964,7 +4964,7 @@ Nemôžete nájsť faktúru? Potrebujete poradiť? Radi Vám pomôžeme
'payment_type_Interac E Transfer' => 'Interac E Transfer', 'payment_type_Interac E Transfer' => 'Interac E Transfer',
'xinvoice_payable' => 'Splatné do :payeddue dní netto do :paydate', 'xinvoice_payable' => 'Splatné do :payeddue dní netto do :paydate',
'xinvoice_no_buyers_reference' => "Nebola uvedená žiadna referencia kupujúceho", 'xinvoice_no_buyers_reference' => "Nebola uvedená žiadna referencia kupujúceho",
'xinvoice_online_payment' => 'Faktúru je potrebné uhradiť online cez uvedený odkaz', 'xinvoice_online_payment' => 'The invoice needs to be paid online via the provided link',
'pre_payment' => 'Platba vopred', 'pre_payment' => 'Platba vopred',
'number_of_payments' => 'Počet platieb', 'number_of_payments' => 'Počet platieb',
'number_of_payments_helper' => 'Koľkokrát sa táto platba uskutoční', 'number_of_payments_helper' => 'Koľkokrát sa táto platba uskutoční',
@ -5048,6 +5048,8 @@ Nemôžete nájsť faktúru? Potrebujete poradiť? Radi Vám pomôžeme
'services' => 'Services', 'services' => 'Services',
'shipping' => 'Shipping', 'shipping' => 'Shipping',
'tax_exempt' => 'Tax Exempt', 'tax_exempt' => 'Tax Exempt',
'late_fee_added_locked_invoice' => 'Late fee for invoice :invoice added on :date',
); );