diff --git a/.github/workflows/react_release.yml b/.github/workflows/react_release.yml index e152890d2a68..2f8a3f8cfc62 100644 --- a/.github/workflows/react_release.yml +++ b/.github/workflows/react_release.yml @@ -64,7 +64,7 @@ jobs: - name: Build project run: | shopt -s dotglob - tar --exclude='public/storage' --exclude='.htaccess' --exclude='invoiceninja.zip' -zcvf /home/runner/work/invoiceninja/react-invoiceninja.tar * + tar --exclude='public/storage' --exclude='./htaccess' --exclude='invoiceninja.zip' -zcvf /home/runner/work/invoiceninja/react-invoiceninja.tar * - name: Release uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/') diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8204134564c3..57ce9b8eb625 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -74,7 +74,7 @@ jobs: run: | zip -r /home/runner/work/invoiceninja/invoiceninja.zip .* -x "../*" shopt -s dotglob - tar --exclude='public/storage' --exclude='.htaccess' --exclude='invoiceninja.zip' -zcvf /home/runner/work/invoiceninja/invoiceninja.tar * + tar --exclude='public/storage' --exclude='./htaccess' --exclude='invoiceninja.zip' -zcvf /home/runner/work/invoiceninja/invoiceninja.tar * - name: Release uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/') diff --git a/VERSION.txt b/VERSION.txt index 68803f5e543f..cc5a1231e025 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.8.53 \ No newline at end of file +5.8.54 \ No newline at end of file diff --git a/app/Console/Commands/CheckData.php b/app/Console/Commands/CheckData.php index 17a450aeb6d9..3e4773e580c3 100644 --- a/app/Console/Commands/CheckData.php +++ b/app/Console/Commands/CheckData.php @@ -208,7 +208,7 @@ class CheckData extends Command ->cursor() ->each(function ($client) { if ($client->recurring_invoices()->where('is_deleted', 0)->where('deleted_at', null)->count() > 1) { - $this->logMessage("Duplicate Recurring Invoice => {$client->custom_value1}"); + $this->logMessage("Duplicate Recurring Invoice => {$client->custom_value1} || {$client->id}}"); } }); } diff --git a/app/DataMapper/Tax/BaseRule.php b/app/DataMapper/Tax/BaseRule.php index 4ec33ab9656d..061fc0c478ed 100644 --- a/app/DataMapper/Tax/BaseRule.php +++ b/app/DataMapper/Tax/BaseRule.php @@ -11,11 +11,12 @@ namespace App\DataMapper\Tax; -use App\DataMapper\Tax\ZipTax\Response; -use App\DataProviders\USStates; +use App\Models\Quote; use App\Models\Client; use App\Models\Invoice; use App\Models\Product; +use App\DataProviders\USStates; +use App\DataMapper\Tax\ZipTax\Response; class BaseRule implements RuleInterface { @@ -210,7 +211,7 @@ class BaseRule implements RuleInterface } /** Applies the tax data to the invoice */ - if($this->invoice instanceof Invoice && $tax_data) { + if(($this->invoice instanceof Invoice || $this->invoice instanceof Quote) && $tax_data) { $this->invoice->tax_data = $tax_data; diff --git a/app/Events/Statement/StatementWasEmailed.php b/app/Events/Statement/StatementWasEmailed.php new file mode 100644 index 000000000000..ea79a211a2d0 --- /dev/null +++ b/app/Events/Statement/StatementWasEmailed.php @@ -0,0 +1,42 @@ + 'task.custom_value4', 'status' => 'task.status_id', 'project' => 'task.project_id', + 'billable' => 'task.billable', ]; protected array $forced_client_fields = [ diff --git a/app/Helpers/SwissQr/SwissQrGenerator.php b/app/Helpers/SwissQr/SwissQrGenerator.php index 17fdb5610f1c..0301de5e1afc 100644 --- a/app/Helpers/SwissQr/SwissQrGenerator.php +++ b/app/Helpers/SwissQr/SwissQrGenerator.php @@ -178,13 +178,13 @@ class SwissQrGenerator if(is_iterable($qrBill->getViolations())) { foreach ($qrBill->getViolations() as $key => $violation) { - nlog("qr"); - nlog($violation); + // nlog("qr"); + // nlog($violation); } } - nlog($e->getMessage()); + // nlog($e->getMessage()); return ''; // return $e->getMessage(); diff --git a/app/Http/Controllers/StripeConnectController.php b/app/Http/Controllers/StripeConnectController.php index bcadff55070c..0ddc95b57e4c 100644 --- a/app/Http/Controllers/StripeConnectController.php +++ b/app/Http/Controllers/StripeConnectController.php @@ -37,18 +37,18 @@ class StripeConnectController extends BaseController MultiDB::findAndSetDbByCompanyKey($request->getTokenContent()['company_key']); - $company_gateway = CompanyGateway::query() - ->where('gateway_key', 'd14dd26a47cecc30fdd65700bfb67b34') - ->where('company_id', $request->getCompany()->id) - ->first(); + // $company_gateway = CompanyGateway::query() + // ->where('gateway_key', 'd14dd26a47cecc30fdd65700bfb67b34') + // ->where('company_id', $request->getCompany()->id) + // ->first(); - if ($company_gateway) { - $config = $company_gateway->getConfig(); + // if ($company_gateway) { + // $config = $company_gateway->getConfig(); - if (property_exists($config, 'account_id') && strlen($config->account_id) > 5) { - return view('auth.connect.existing'); - } - } + // if (property_exists($config, 'account_id') && strlen($config->account_id) > 5) { + // return view('auth.connect.existing'); + // } + // } $stripe_client_id = config('ninja.ninja_stripe_client_id'); $redirect_uri = config('ninja.app_url').'/stripe/completed'; @@ -127,7 +127,6 @@ class StripeConnectController extends BaseController 'refresh_token' => $response->refresh_token, 'access_token' => $response->access_token, 'appleDomainVerification' => '', - // "statementDescriptor" => "", ]; $company_gateway->setConfig($payload); @@ -145,9 +144,6 @@ class StripeConnectController extends BaseController nlog("could not harvest stripe company name"); } - // nlog("Stripe Connect Redirect URI = {$redirect_uri}"); - - // StripeWebhook::dispatch($company->company_key, $company_gateway->id); if(isset($request->getTokenContent()['is_react']) && $request->getTokenContent()['is_react']) { $redirect_uri = config('ninja.react_url').'/#/settings/online_payments'; } else { @@ -158,7 +154,7 @@ class StripeConnectController extends BaseController //response here return view('auth.connect.completed', ['url' => $redirect_uri]); - // return redirect($redirect_uri); + } } diff --git a/app/Http/Controllers/TwilioController.php b/app/Http/Controllers/TwilioController.php index ddd0df7ab763..8efb09a7135d 100644 --- a/app/Http/Controllers/TwilioController.php +++ b/app/Http/Controllers/TwilioController.php @@ -129,6 +129,10 @@ class TwilioController extends BaseController $user->verified_phone_number = true; $user->save(); + if (class_exists(\Modules\Admin\Jobs\Account\UserQualityCheck::class)) { + \Modules\Admin\Jobs\Account\UserQualityCheck::dispatch($user, $user->company()->db); + } + return response()->json(['message' => 'SMS verified'], 200); } diff --git a/app/Http/Requests/BankTransaction/StoreBankTransactionRequest.php b/app/Http/Requests/BankTransaction/StoreBankTransactionRequest.php index c3edb7bd9dee..55deb420ab4a 100644 --- a/app/Http/Requests/BankTransaction/StoreBankTransactionRequest.php +++ b/app/Http/Requests/BankTransaction/StoreBankTransactionRequest.php @@ -41,7 +41,7 @@ class StoreBankTransactionRequest extends Request $rules = []; $rules['bank_integration_id'] = 'bail|required|exists:bank_integrations,id,company_id,'.$user->company()->id.',is_deleted,0'; - + $rules['amount'] = ['sometimes', 'bail', 'numeric', 'nullable', 'max:99999999999999']; return $rules; } @@ -55,6 +55,7 @@ class StoreBankTransactionRequest extends Request $input['bank_integration_id'] = $this->decodePrimaryKey($input['bank_integration_id']); } + $this->replace($input); } } diff --git a/app/Http/Requests/BankTransaction/UpdateBankTransactionRequest.php b/app/Http/Requests/BankTransaction/UpdateBankTransactionRequest.php index 9cfab70d59fe..03544f2d07f9 100644 --- a/app/Http/Requests/BankTransaction/UpdateBankTransactionRequest.php +++ b/app/Http/Requests/BankTransaction/UpdateBankTransactionRequest.php @@ -44,9 +44,7 @@ class UpdateBankTransactionRequest extends Request $rules['vendor_id'] = 'bail|required|exists:vendors,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; } - // if (isset($this->expense_id)) { - // $rules['expense_id'] = 'bail|required|exists:expenses,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; - // } + $rules['amount'] = ['sometimes', 'bail', 'nullable', 'numeric', 'max:99999999999999']; $rules['bank_integration_id'] = 'bail|required|exists:bank_integrations,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; diff --git a/app/Http/Requests/Credit/StoreCreditRequest.php b/app/Http/Requests/Credit/StoreCreditRequest.php index 9baf0c706f44..534a7bc77eba 100644 --- a/app/Http/Requests/Credit/StoreCreditRequest.php +++ b/app/Http/Requests/Credit/StoreCreditRequest.php @@ -67,7 +67,7 @@ class StoreCreditRequest extends Request // $rules['number'] = new UniqueCreditNumberRule($this->all()); $rules['number'] = ['nullable', Rule::unique('credits')->where('company_id', $user->company()->id)]; - $rules['discount'] = 'sometimes|numeric'; + $rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['is_amount_discount'] = ['boolean']; $rules['tax_rate1'] = 'bail|sometimes|numeric'; $rules['tax_rate2'] = 'bail|sometimes|numeric'; @@ -76,6 +76,7 @@ class StoreCreditRequest extends Request $rules['tax_name2'] = 'bail|sometimes|string|nullable'; $rules['tax_name3'] = 'bail|sometimes|string|nullable'; $rules['exchange_rate'] = 'bail|sometimes|numeric'; + $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; if ($this->invoice_id) { $rules['invoice_id'] = new ValidInvoiceCreditRule(); @@ -101,6 +102,7 @@ class StoreCreditRequest extends Request $input = $this->decodePrimaryKeys($input); $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; + $input['amount'] = $this->entityTotalAmount($input['line_items']); if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) { $input['exchange_rate'] = 1; diff --git a/app/Http/Requests/Credit/UpdateCreditRequest.php b/app/Http/Requests/Credit/UpdateCreditRequest.php index 9dafd1583eb3..bfbd1f268d5b 100644 --- a/app/Http/Requests/Credit/UpdateCreditRequest.php +++ b/app/Http/Requests/Credit/UpdateCreditRequest.php @@ -67,7 +67,8 @@ class UpdateCreditRequest extends Request $rules['client_id'] = ['bail', 'sometimes',Rule::in([$this->credit->client_id])]; $rules['line_items'] = 'array'; - $rules['discount'] = 'sometimes|numeric'; + +$rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['is_amount_discount'] = ['boolean']; $rules['tax_rate1'] = 'bail|sometimes|numeric'; $rules['tax_rate2'] = 'bail|sometimes|numeric'; @@ -76,6 +77,7 @@ class UpdateCreditRequest extends Request $rules['tax_name2'] = 'bail|sometimes|string|nullable'; $rules['tax_name3'] = 'bail|sometimes|string|nullable'; $rules['exchange_rate'] = 'bail|sometimes|numeric'; + $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; return $rules; } @@ -92,6 +94,8 @@ class UpdateCreditRequest extends Request if (isset($input['line_items'])) { $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; + $input['amount'] = $this->entityTotalAmount($input['line_items']); + } if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) { diff --git a/app/Http/Requests/Expense/StoreExpenseRequest.php b/app/Http/Requests/Expense/StoreExpenseRequest.php index 5667e4b1efb5..b3aec1fce99e 100644 --- a/app/Http/Requests/Expense/StoreExpenseRequest.php +++ b/app/Http/Requests/Expense/StoreExpenseRequest.php @@ -53,6 +53,7 @@ class StoreExpenseRequest extends Request $rules['payment_date'] = 'bail|nullable|sometimes|date:Y-m-d'; $rules['date'] = 'bail|sometimes|date:Y-m-d'; $rules['documents'] = 'bail|sometimes|array'; + $rules['amount'] = ['sometimes', 'bail', 'nullable', 'numeric', 'max:99999999999999']; return $this->globalRules($rules); } diff --git a/app/Http/Requests/Expense/UpdateExpenseRequest.php b/app/Http/Requests/Expense/UpdateExpenseRequest.php index 25ca66022a06..ced5c9bd1a70 100644 --- a/app/Http/Requests/Expense/UpdateExpenseRequest.php +++ b/app/Http/Requests/Expense/UpdateExpenseRequest.php @@ -55,7 +55,7 @@ class UpdateExpenseRequest extends Request $rules['transaction_id'] = 'bail|sometimes|nullable|exists:bank_transactions,id,company_id,'.$user->company()->id; $rules['invoice_id'] = 'bail|sometimes|nullable|exists:invoices,id,company_id,'.$user->company()->id; $rules['documents'] = 'bail|sometimes|array'; - + $rules['amount'] = ['sometimes', 'bail', 'nullable', 'numeric', 'max:99999999999999']; return $this->globalRules($rules); } diff --git a/app/Http/Requests/Invoice/StoreInvoiceRequest.php b/app/Http/Requests/Invoice/StoreInvoiceRequest.php index f91faa9cc1f6..f7bcb565d88d 100644 --- a/app/Http/Requests/Invoice/StoreInvoiceRequest.php +++ b/app/Http/Requests/Invoice/StoreInvoiceRequest.php @@ -67,7 +67,7 @@ class StoreInvoiceRequest extends Request $rules['is_amount_discount'] = ['boolean']; $rules['line_items'] = 'array'; - $rules['discount'] = 'sometimes|numeric'; + $rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['tax_rate1'] = 'bail|sometimes|numeric'; $rules['tax_rate2'] = 'bail|sometimes|numeric'; $rules['tax_rate3'] = 'bail|sometimes|numeric'; @@ -77,9 +77,11 @@ class StoreInvoiceRequest extends Request $rules['exchange_rate'] = 'bail|sometimes|numeric'; $rules['partial'] = 'bail|sometimes|nullable|numeric|gte:0'; $rules['partial_due_date'] = ['bail', 'sometimes', 'exclude_if:partial,0', Rule::requiredIf(fn () => $this->partial > 0), 'date']; + $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; + + // $rules['amount'] = ['sometimes', 'bail', 'max:99999999999999']; // $rules['due_date'] = ['bail', 'sometimes', 'nullable', 'after:partial_due_date', Rule::requiredIf(fn () => strlen($this->partial_due_date) > 1), 'date']; - return $rules; } @@ -89,17 +91,18 @@ class StoreInvoiceRequest extends Request $input = $this->decodePrimaryKeys($input); + $input['amount'] = 0; + $input['balance'] = 0; + if (isset($input['line_items']) && is_array($input['line_items'])) { $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; + $input['amount'] = $this->entityTotalAmount($input['line_items']); } if(isset($input['partial']) && $input['partial'] == 0) { $input['partial_due_date'] = null; } - $input['amount'] = 0; - $input['balance'] = 0; - if (array_key_exists('tax_rate1', $input) && is_null($input['tax_rate1'])) { $input['tax_rate1'] = 0; } diff --git a/app/Http/Requests/Invoice/UpdateInvoiceRequest.php b/app/Http/Requests/Invoice/UpdateInvoiceRequest.php index f21feb1933f6..c06605cf611b 100644 --- a/app/Http/Requests/Invoice/UpdateInvoiceRequest.php +++ b/app/Http/Requests/Invoice/UpdateInvoiceRequest.php @@ -66,7 +66,8 @@ class UpdateInvoiceRequest extends Request $rules['is_amount_discount'] = ['boolean']; $rules['client_id'] = ['bail', 'sometimes', Rule::in([$this->invoice->client_id])]; $rules['line_items'] = 'array'; - $rules['discount'] = 'sometimes|numeric'; + +$rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())]; $rules['tax_rate1'] = 'bail|sometimes|numeric'; $rules['tax_rate2'] = 'bail|sometimes|numeric'; @@ -77,6 +78,8 @@ class UpdateInvoiceRequest extends Request $rules['status_id'] = 'bail|sometimes|not_in:5'; //do not allow cancelled invoices to be modfified. $rules['exchange_rate'] = 'bail|sometimes|numeric'; $rules['partial'] = 'bail|sometimes|nullable|numeric'; + $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; + // $rules['partial_due_date'] = ['bail', 'sometimes', 'exclude_if:partial,0', Rule::requiredIf(fn () => $this->partial > 0), 'date', 'before:due_date']; // $rules['due_date'] = ['bail', 'sometimes', 'nullable', 'after:partial_due_date', Rule::requiredIf(fn () => strlen($this->partial_due_date) > 1), 'date']; @@ -97,6 +100,7 @@ class UpdateInvoiceRequest extends Request if (isset($input['line_items']) && is_array($input['line_items'])) { $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; + $input['amount'] = $this->entityTotalAmount($input['line_items']); } if (array_key_exists('documents', $input)) { diff --git a/app/Http/Requests/Payment/RefundPaymentRequest.php b/app/Http/Requests/Payment/RefundPaymentRequest.php index 71fdf39e2995..2cee811ea878 100644 --- a/app/Http/Requests/Payment/RefundPaymentRequest.php +++ b/app/Http/Requests/Payment/RefundPaymentRequest.php @@ -67,9 +67,8 @@ class RefundPaymentRequest extends Request $input = $this->all(); $rules = [ - 'id' => 'bail|required', //@phpstan-ignore-line - 'id' => new ValidRefundableRequest($input), - 'amount' => 'numeric', + 'id' => ['bail','required', new ValidRefundableRequest($input)], + 'amount' => ['numeric', 'max:99999999999999'], 'date' => 'required', 'invoices.*.invoice_id' => 'required', 'invoices.*.amount' => 'required', diff --git a/app/Http/Requests/Payment/StorePaymentRequest.php b/app/Http/Requests/Payment/StorePaymentRequest.php index 152a8aecff43..10fe585229b5 100644 --- a/app/Http/Requests/Payment/StorePaymentRequest.php +++ b/app/Http/Requests/Payment/StorePaymentRequest.php @@ -50,7 +50,7 @@ class StorePaymentRequest extends Request 'invoices.*.invoice_id' => ['bail','required','distinct', new ValidInvoicesRules($this->all()),Rule::exists('invoices','id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)], 'credits.*.credit_id' => ['bail','required','distinct', new ValidCreditsRules($this->all()),Rule::exists('credits','id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)], 'credits.*.amount' => ['bail','required', new CreditsSumRule($this->all())], - 'amount' => ['bail', 'numeric', new PaymentAmountsBalanceRule()], + 'amount' => ['bail', 'numeric', new PaymentAmountsBalanceRule(), 'max:99999999999999'], 'number' => ['bail', 'nullable', Rule::unique('payments')->where('company_id', $user->company()->id)], 'idempotency_key' => ['nullable', 'bail', 'string','max:64', Rule::unique('payments')->where('company_id', $user->company()->id)], ]; diff --git a/app/Http/Requests/PurchaseOrder/StorePurchaseOrderRequest.php b/app/Http/Requests/PurchaseOrder/StorePurchaseOrderRequest.php index d21c73cbf68d..50ff98993f7a 100644 --- a/app/Http/Requests/PurchaseOrder/StorePurchaseOrderRequest.php +++ b/app/Http/Requests/PurchaseOrder/StorePurchaseOrderRequest.php @@ -49,7 +49,8 @@ class StorePurchaseOrderRequest extends Request $rules['vendor_id'] = 'bail|required|exists:vendors,id,company_id,'.$user->company()->id.',is_deleted,0'; $rules['number'] = ['nullable', Rule::unique('purchase_orders')->where('company_id', $user->company()->id)]; - $rules['discount'] = 'sometimes|numeric'; + +$rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['is_amount_discount'] = ['boolean']; $rules['line_items'] = 'array'; @@ -70,6 +71,8 @@ class StorePurchaseOrderRequest extends Request $rules['status_id'] = 'nullable|integer|in:1,2,3,4,5'; $rules['exchange_rate'] = 'bail|sometimes|numeric'; + $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; + return $rules; } @@ -79,16 +82,18 @@ class StorePurchaseOrderRequest extends Request $input = $this->decodePrimaryKeys($input); + $input['amount'] = 0; + $input['balance'] = 0; + if(isset($input['partial']) && $input['partial'] == 0) { $input['partial_due_date'] = null; } if (isset($input['line_items']) && is_array($input['line_items'])) { $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; - } + $input['amount'] = $this->entityTotalAmount($input['line_items']); - $input['amount'] = 0; - $input['balance'] = 0; + } if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) { $input['exchange_rate'] = 1; diff --git a/app/Http/Requests/PurchaseOrder/UpdatePurchaseOrderRequest.php b/app/Http/Requests/PurchaseOrder/UpdatePurchaseOrderRequest.php index a9be48fb7f18..c0ab87926983 100644 --- a/app/Http/Requests/PurchaseOrder/UpdatePurchaseOrderRequest.php +++ b/app/Http/Requests/PurchaseOrder/UpdatePurchaseOrderRequest.php @@ -52,7 +52,8 @@ class UpdatePurchaseOrderRequest extends Request $rules['vendor_id'] = ['bail', 'sometimes', Rule::in([$this->purchase_order->vendor_id])]; $rules['line_items'] = 'array'; - $rules['discount'] = 'sometimes|numeric'; + +$rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['is_amount_discount'] = ['boolean']; if ($this->file('documents') && is_array($this->file('documents'))) { @@ -71,6 +72,7 @@ class UpdatePurchaseOrderRequest extends Request $rules['status_id'] = 'sometimes|integer|in:1,2,3,4,5'; $rules['exchange_rate'] = 'bail|sometimes|numeric'; + $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; return $rules; } @@ -89,6 +91,7 @@ class UpdatePurchaseOrderRequest extends Request if (isset($input['line_items']) && is_array($input['line_items'])) { $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; + $input['amount'] = $this->entityTotalAmount($input['line_items']); } if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) { diff --git a/app/Http/Requests/Quote/StoreQuoteRequest.php b/app/Http/Requests/Quote/StoreQuoteRequest.php index 3fa933356469..221ea3815308 100644 --- a/app/Http/Requests/Quote/StoreQuoteRequest.php +++ b/app/Http/Requests/Quote/StoreQuoteRequest.php @@ -60,12 +60,14 @@ class StoreQuoteRequest extends Request } $rules['number'] = ['nullable', Rule::unique('quotes')->where('company_id', $user->company()->id)]; - $rules['discount'] = 'sometimes|numeric'; + +$rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['is_amount_discount'] = ['boolean']; $rules['exchange_rate'] = 'bail|sometimes|numeric'; $rules['line_items'] = 'array'; $rules['partial_due_date'] = ['bail', 'sometimes', 'exclude_if:partial,0', Rule::requiredIf(fn () => $this->partial > 0), 'date', 'before:due_date', 'after_or_equal:date']; $rules['due_date'] = ['bail', 'sometimes', 'nullable', 'after:partial_due_date', Rule::requiredIf(fn () => strlen($this->partial_due_date) > 1), 'date']; + $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; return $rules; } @@ -79,10 +81,14 @@ class StoreQuoteRequest extends Request $input = $this->decodePrimaryKeys($input); - $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; $input['amount'] = 0; $input['balance'] = 0; + if (isset($input['line_items']) && is_array($input['line_items'])) { + $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; + $input['amount'] = $this->entityTotalAmount($input['line_items']); + } + if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) { $input['exchange_rate'] = 1; } diff --git a/app/Http/Requests/Quote/UpdateQuoteRequest.php b/app/Http/Requests/Quote/UpdateQuoteRequest.php index 4a8b386c9206..d1e3fe9967d8 100644 --- a/app/Http/Requests/Quote/UpdateQuoteRequest.php +++ b/app/Http/Requests/Quote/UpdateQuoteRequest.php @@ -59,12 +59,13 @@ class UpdateQuoteRequest extends Request $rules['number'] = ['bail', 'sometimes', 'nullable', Rule::unique('quotes')->where('company_id', $user->company()->id)->ignore($this->quote->id)]; $rules['client_id'] = ['bail', 'sometimes', Rule::in([$this->quote->client_id])]; $rules['line_items'] = 'array'; - $rules['discount'] = 'sometimes|numeric'; + $rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['is_amount_discount'] = ['boolean']; $rules['exchange_rate'] = 'bail|sometimes|numeric'; $rules['partial_due_date'] = ['bail', 'sometimes', 'exclude_if:partial,0', Rule::requiredIf(fn () => $this->partial > 0), 'date', 'before:due_date']; $rules['due_date'] = ['bail', 'sometimes', 'nullable', 'after:partial_due_date', 'after_or_equal:date', Rule::requiredIf(fn () => strlen($this->partial_due_date) > 1), 'date']; + $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; return $rules; } @@ -79,6 +80,7 @@ class UpdateQuoteRequest extends Request if (isset($input['line_items'])) { $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; + $input['amount'] = $this->entityTotalAmount($input['line_items']); } if (array_key_exists('documents', $input)) { diff --git a/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php index e6319c7bea94..5b56080959e0 100644 --- a/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php +++ b/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php @@ -79,6 +79,8 @@ class StoreRecurringInvoiceRequest extends Request $rules['exchange_rate'] = 'bail|sometimes|numeric'; $rules['next_send_date'] = 'bail|required|date|after:yesterday'; + $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; + return $rules; } @@ -145,6 +147,7 @@ class StoreRecurringInvoiceRequest extends Request } $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; + $input['amount'] = $this->entityTotalAmount($input['line_items']); if (isset($input['auto_bill'])) { $input['auto_bill_enabled'] = $this->setAutoBillFlag($input['auto_bill']); diff --git a/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php index ee4c01c3766b..9e6238570955 100644 --- a/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php +++ b/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php @@ -72,6 +72,7 @@ class UpdateRecurringInvoiceRequest extends Request $rules['tax_name3'] = 'bail|sometimes|string|nullable'; $rules['exchange_rate'] = 'bail|sometimes|numeric'; $rules['next_send_date'] = 'bail|required|date|after:yesterday'; + $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; return $rules; } @@ -126,6 +127,7 @@ class UpdateRecurringInvoiceRequest extends Request if (isset($input['line_items'])) { $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; + $input['amount'] = $this->entityTotalAmount($input['line_items']); } if (array_key_exists('auto_bill', $input) && isset($input['auto_bill'])) { diff --git a/app/Import/Transformer/Csv/ExpenseTransformer.php b/app/Import/Transformer/Csv/ExpenseTransformer.php index 5f32f49bd44a..c641662b41f8 100644 --- a/app/Import/Transformer/Csv/ExpenseTransformer.php +++ b/app/Import/Transformer/Csv/ExpenseTransformer.php @@ -42,7 +42,7 @@ class ExpenseTransformer extends BaseTransformer 'client_id' => isset($data['expense.client']) ? $this->getClientId($data['expense.client']) : null, - 'date' => strlen($this->getString($data, 'expense.date') > 1) ? date('Y-m-d', strtotime(str_replace("/", "-", $data['expense.date']))) : now()->format('Y-m-d'), + 'date' => strlen($this->getString($data, 'expense.date') > 1) ? $this->parseDate($data['expense.date']) : now()->format('Y-m-d'), 'public_notes' => $this->getString($data, 'expense.public_notes'), 'private_notes' => $this->getString($data, 'expense.private_notes'), 'category_id' => isset($data['expense.category']) @@ -55,7 +55,7 @@ class ExpenseTransformer extends BaseTransformer ? $this->getPaymentTypeId($data['expense.payment_type']) : null, 'payment_date' => isset($data['expense.payment_date']) - ? date('Y-m-d', strtotime(str_replace("/", "-", $data['expense.payment_date']))) + ? $this->parseDate($data['expense.payment_date']) : null, 'custom_value1' => $this->getString($data, 'expense.custom_value1'), 'custom_value2' => $this->getString($data, 'expense.custom_value2'), diff --git a/app/Import/Transformer/Csv/InvoiceTransformer.php b/app/Import/Transformer/Csv/InvoiceTransformer.php index 5dbced3ca7e8..50a85a0922ca 100644 --- a/app/Import/Transformer/Csv/InvoiceTransformer.php +++ b/app/Import/Transformer/Csv/InvoiceTransformer.php @@ -93,11 +93,8 @@ class InvoiceTransformer extends BaseTransformer 'invoice.custom_value4' ), 'footer' => $this->getString($invoice_data, 'invoice.footer'), - 'partial' => $this->getFloat($invoice_data, 'invoice.partial') > 0 ?: null, - 'partial_due_date' => $this->getString( - $invoice_data, - 'invoice.partial_due_date' - ), + 'partial' => $this->getFloat($invoice_data, 'invoice.partial') > 0 ? $this->getFloat($invoice_data, 'invoice.partial') : null, + 'partial_due_date' => isset($invoice_data['invoice.partial_due_date']) ? $this->parseDate($invoice_data['invoice.partial_due_date']) : null, 'custom_surcharge1' => $this->getFloat( $invoice_data, 'invoice.custom_surcharge1' diff --git a/app/Import/Transformer/Csv/QuoteTransformer.php b/app/Import/Transformer/Csv/QuoteTransformer.php index 93e24120d0bf..1ee131f390cd 100644 --- a/app/Import/Transformer/Csv/QuoteTransformer.php +++ b/app/Import/Transformer/Csv/QuoteTransformer.php @@ -56,10 +56,10 @@ class QuoteTransformer extends BaseTransformer 'discount' => $this->getFloat($quote_data, 'quote.discount'), 'po_number' => $this->getString($quote_data, 'quote.po_number'), 'date' => isset($quote_data['quote.date']) - ? date('Y-m-d', strtotime(str_replace("/", "-", $quote_data['quote.date']))) + ? $this->parseDate($quote_data['quote.date']) : now()->format('Y-m-d'), 'due_date' => isset($quote_data['quote.due_date']) - ? date('Y-m-d', strtotime(str_replace("/", "-", $quote_data['quote.due_date']))) + ? $this->parseDate($quote_data['quote.due_date']) : null, 'terms' => $this->getString($quote_data, 'quote.terms'), 'public_notes' => $this->getString( @@ -94,10 +94,7 @@ class QuoteTransformer extends BaseTransformer ), 'footer' => $this->getString($quote_data, 'quote.footer'), 'partial' => $this->getFloat($quote_data, 'quote.partial'), - 'partial_due_date' => $this->getString( - $quote_data, - 'quote.partial_due_date' - ), + 'partial_due_date' => isset($invoice_data['quote.partial_due_date']) ? $this->parseDate($quote_data['quote.partial_due_date']) : null, 'custom_surcharge1' => $this->getString( $quote_data, 'quote.custom_surcharge1' @@ -139,10 +136,7 @@ class QuoteTransformer extends BaseTransformer $transformed['payments'] = [ [ 'date' => isset($quote_data['payment.date']) - ? date( - 'Y-m-d', - strtotime($quote_data['payment.date']) - ) + ? $this->parseDate($quote_data['payment.date']) : date('y-m-d'), 'transaction_reference' => $this->getString( $quote_data, @@ -158,10 +152,7 @@ class QuoteTransformer extends BaseTransformer $transformed['payments'] = [ [ 'date' => isset($quote_data['payment.date']) - ? date( - 'Y-m-d', - strtotime($quote_data['payment.date']) - ) + ? $this->parseDate($quote_data['payment.date']) : date('y-m-d'), 'transaction_reference' => $this->getString( $quote_data, @@ -181,10 +172,7 @@ class QuoteTransformer extends BaseTransformer $transformed['payments'] = [ [ 'date' => isset($quote_data['payment.date']) - ? date( - 'Y-m-d', - strtotime($quote_data['payment.date']) - ) + ? $this->parseDate($quote_data['payment.date']) : date('y-m-d'), 'transaction_reference' => $this->getString( $quote_data, diff --git a/app/Import/Transformer/Csv/RecurringInvoiceTransformer.php b/app/Import/Transformer/Csv/RecurringInvoiceTransformer.php index 2f924da831d6..74f1a9b05ff1 100644 --- a/app/Import/Transformer/Csv/RecurringInvoiceTransformer.php +++ b/app/Import/Transformer/Csv/RecurringInvoiceTransformer.php @@ -65,9 +65,7 @@ class RecurringInvoiceTransformer extends BaseTransformer 'next_send_date_client' => isset($invoice_data['invoice.next_send_date']) ? $this->parseDate($invoice_data['invoice.next_send_date']) : now()->format('Y-m-d'), - 'due_date' => isset($invoice_data['invoice.due_date']) - ? $this->parseDate($invoice_data['invoice.due_date']) - : null, + 'due_date' => isset($invoice_data['invoice.due_date']) ? $this->parseDate($invoice_data['invoice.due_date']) : null, 'terms' => $this->getString($invoice_data, 'invoice.terms'), 'due_date_days' => 'terms', 'public_notes' => $this->getString( @@ -101,11 +99,8 @@ class RecurringInvoiceTransformer extends BaseTransformer 'invoice.custom_value4' ), 'footer' => $this->getString($invoice_data, 'invoice.footer'), - 'partial' => $this->getFloat($invoice_data, 'invoice.partial') > 0 ?: null, - 'partial_due_date' => $this->getString( - $invoice_data, - 'invoice.partial_due_date' - ), + 'partial' => $this->getFloat($invoice_data, 'invoice.partial') > 0 ? $this->getFloat($invoice_data, 'invoice.partial') : null, + 'partial_due_date' => isset($invoice_data['invoice.partial_due_date']) ? $this->parseDate($invoice_data['invoice.partial_due_date']) : null, 'custom_surcharge1' => $this->getString( $invoice_data, 'invoice.custom_surcharge1' diff --git a/app/Import/Transformer/Csv/TaskTransformer.php b/app/Import/Transformer/Csv/TaskTransformer.php index d2c6d4538f33..edd8737131cb 100644 --- a/app/Import/Transformer/Csv/TaskTransformer.php +++ b/app/Import/Transformer/Csv/TaskTransformer.php @@ -49,7 +49,7 @@ class TaskTransformer extends BaseTransformer 'client_id' => $clientId, 'project_id' => $this->getProjectId($projectId, $clientId), 'description' => $this->getString($task_data, 'task.description'), - 'status' => $this->getTaskStatusId($task_data), + 'status_id' => $this->getTaskStatusId($task_data), 'custom_value1' => $this->getString($task_data, 'task.custom_value1'), 'custom_value2' => $this->getString($task_data, 'task.custom_value2'), 'custom_value3' => $this->getString($task_data, 'task.custom_value3'), @@ -84,7 +84,7 @@ class TaskTransformer extends BaseTransformer } elseif(isset($item['task.billable']) && is_bool($item['task.billable'])) { $is_billable = $item['task.billable']; } else { - $is_billable = false; + $is_billable = true; } if(isset($item['task.start_date']) && diff --git a/app/Import/Transformer/Freshbooks/InvoiceTransformer.php b/app/Import/Transformer/Freshbooks/InvoiceTransformer.php index 429d681f1056..4f348722655a 100644 --- a/app/Import/Transformer/Freshbooks/InvoiceTransformer.php +++ b/app/Import/Transformer/Freshbooks/InvoiceTransformer.php @@ -42,8 +42,7 @@ class InvoiceTransformer extends BaseTransformer 'company_id' => $this->company->id, 'client_id' => $this->getClient($this->getString($invoice_data, 'Client Name'), null), 'number' => $this->getString($invoice_data, 'Invoice #'), - 'date' => isset($invoice_data['Date Issued']) ? date('Y-m-d', strtotime($invoice_data['Date Issued'])) : null, - // 'currency_id' => $this->getCurrencyByCode( $invoice_data, 'Currency' ), + 'date' => isset($invoice_data['Date Issued']) ? $this->parseDate($invoice_data['Date Issued']) : null, 'amount' => 0, 'status_id' => $invoiceStatusMap[$status = strtolower($this->getString($invoice_data, 'Invoice Status'))] ?? Invoice::STATUS_SENT, @@ -70,7 +69,7 @@ class InvoiceTransformer extends BaseTransformer if (! empty($invoice_data['Date Paid'])) { $transformed['payments'] = [[ - 'date' => date('Y-m-d', strtotime($invoice_data['Date Paid'])), + 'date' => $this->parseDate($invoice_data['Date Paid']), 'amount' => $transformed['amount'], ]]; } diff --git a/app/Import/Transformer/Invoice2Go/InvoiceTransformer.php b/app/Import/Transformer/Invoice2Go/InvoiceTransformer.php index 0eb46134e223..da50ebb95603 100644 --- a/app/Import/Transformer/Invoice2Go/InvoiceTransformer.php +++ b/app/Import/Transformer/Invoice2Go/InvoiceTransformer.php @@ -45,7 +45,7 @@ class InvoiceTransformer extends BaseTransformer 'company_id' => $this->company->id, 'number' => $this->getString($invoice_data, 'DocumentNumber'), 'notes' => $this->getString($invoice_data, 'Comment'), - 'date' => isset($invoice_data['DocumentDate']) ? date('Y-m-d', strtotime($invoice_data['DocumentDate'])) : null, + 'date' => isset($invoice_data['DocumentDate']) ? $this->parseDate($invoice_data['DocumentDate']) : null, // 'currency_id' => $this->getCurrencyByCode( $invoice_data, 'Currency' ), 'amount' => $this->getFloat($invoice_data, 'TotalAmount'), 'status_id' => $invoiceStatusMap[$status = @@ -92,7 +92,7 @@ class InvoiceTransformer extends BaseTransformer if (! empty($invoice_data['Date Paid'])) { $transformed['payments'] = [ [ - 'date' => date('Y-m-d', strtotime($invoice_data['DatePaid'])), + 'date' => $this->parseDate($invoice_data['DatePaid']), 'amount' => $this->getFloat($invoice_data, 'Payments'), ], ]; diff --git a/app/Import/Transformer/Invoicely/InvoiceTransformer.php b/app/Import/Transformer/Invoicely/InvoiceTransformer.php index 04a4d9f083ff..bd292834f35d 100644 --- a/app/Import/Transformer/Invoicely/InvoiceTransformer.php +++ b/app/Import/Transformer/Invoicely/InvoiceTransformer.php @@ -35,8 +35,8 @@ class InvoiceTransformer extends BaseTransformer 'company_id' => $this->company->id, 'client_id' => $this->getClient($this->getString($data, 'Client'), null), 'number' => $this->getString($data, 'Details'), - 'date' => isset($data['Date']) ? date('Y-m-d', strtotime($data['Date'])) : null, - 'due_date' => isset($data['Due']) ? date('Y-m-d', strtotime($data['Due'])) : null, + 'date' => isset($data['Date']) ? $this->parseDate($data['Date']) : null, + 'due_date' => isset($data['Due']) ? $this->parseDate($data['Due']) : null, 'status_id' => Invoice::STATUS_SENT, 'line_items' => [ [ diff --git a/app/Import/Transformer/Wave/ExpenseTransformer.php b/app/Import/Transformer/Wave/ExpenseTransformer.php index 1a67c5281037..8f37c94b788a 100644 --- a/app/Import/Transformer/Wave/ExpenseTransformer.php +++ b/app/Import/Transformer/Wave/ExpenseTransformer.php @@ -43,7 +43,7 @@ class ExpenseTransformer extends BaseTransformer 'vendor_id' => $this->getVendorIdOrCreate($this->getString($data, 'Vendor')), 'number' => $this->getString($data, 'Bill Number'), 'public_notes' => $this->getString($data, 'Notes / Memo'), - 'date' => date('Y-m-d', strtotime($data['Transaction Date Added'])) ?: now()->format('Y-m-d'), //27-01-2022 + 'date' => $this->parseDate($data['Transaction Date Added']) ?: now()->format('Y-m-d'), //27-01-2022 'currency_id' => $this->company->settings->currency_id, 'category_id' => $this->getOrCreateExpenseCategry($data['Account Name']), 'amount' => $amount, diff --git a/app/Import/Transformer/Wave/InvoiceTransformer.php b/app/Import/Transformer/Wave/InvoiceTransformer.php index 9677a2c529df..c1d5df1e4031 100644 --- a/app/Import/Transformer/Wave/InvoiceTransformer.php +++ b/app/Import/Transformer/Wave/InvoiceTransformer.php @@ -49,10 +49,10 @@ class InvoiceTransformer extends BaseTransformer 'company_id' => $this->company->id, 'client_id' => $this->getClient($customer_name = $this->getString($invoice_data, $customer_key), null), 'number' => $invoice_number = $this->getString($invoice_data, 'Invoice Number'), - 'date' => date('Y-m-d', strtotime($invoice_data[$date_key])) ?: now()->format('Y-m-d'), //27-01-2022 + 'date' => $this->parseDate($invoice_data[$date_key]) ?: now()->format('Y-m-d'), //27-01-2022 'currency_id' => $this->getCurrencyByCode($invoice_data, 'Currency'), 'status_id' => Invoice::STATUS_SENT, - 'due_date' => array_key_exists('Due Date', $invoice_data) ? date('Y-m-d', strtotime($invoice_data['Due Date'])) : null, + 'due_date' => array_key_exists('Due Date', $invoice_data) ? $this->parseDate($invoice_data['Due Date']) : null, ]; $line_items = []; @@ -81,7 +81,7 @@ class InvoiceTransformer extends BaseTransformer } elseif (array_key_exists('Account Type', $record) && $record['Account Type'] === 'System Receivable Invoice') { // This is a payment $payments[] = [ - 'date' => date('Y-m-d', strtotime($invoice_data[$date_key])), + 'date' => $this->parseDate($invoice_data[$date_key]), 'amount' => $this->getFloat($record, 'Amount (One column)'), ]; } else { @@ -103,7 +103,7 @@ class InvoiceTransformer extends BaseTransformer if (array_key_exists('Invoice Paid', $record) && $record['Invoice Paid'] > 0) { $payments[] = [ - 'date' => date('Y-m-d', strtotime($record['Last Payment Date'])), + 'date' => $this->parseDate($record['Last Payment Date']), 'amount' => $this->getFloat($record, 'Invoice Paid'), ]; } diff --git a/app/Import/Transformer/Zoho/InvoiceTransformer.php b/app/Import/Transformer/Zoho/InvoiceTransformer.php index 9e1eedfacf0c..bf70fb235a0e 100644 --- a/app/Import/Transformer/Zoho/InvoiceTransformer.php +++ b/app/Import/Transformer/Zoho/InvoiceTransformer.php @@ -43,8 +43,8 @@ class InvoiceTransformer extends BaseTransformer // 'client_id' => $this->getClient($this->getString($invoice_data, 'Customer ID'), $this->getString($invoice_data, 'Primary Contact EmailID')), 'client_id' => $this->harvestClient($invoice_data), 'number' => $this->getString($invoice_data, 'Invoice Number'), - 'date' => isset($invoice_data['Invoice Date']) ? date('Y-m-d', strtotime($invoice_data['Invoice Date'])) : null, - 'due_date' => isset($invoice_data['Due Date']) ? date('Y-m-d', strtotime($invoice_data['Due Date'])) : null, + 'date' => isset($invoice_data['Invoice Date']) ? $this->parseDate($invoice_data['Invoice Date']) : null, + 'due_date' => isset($invoice_data['Due Date']) ? $this->parseDate($invoice_data['Due Date']) : null, 'po_number' => $this->getString($invoice_data, 'PurchaseOrder'), 'public_notes' => $this->getString($invoice_data, 'Notes'), 'currency_id' => $this->getCurrencyByCode($invoice_data, 'Currency'), @@ -74,7 +74,7 @@ class InvoiceTransformer extends BaseTransformer if ($transformed['balance'] < $transformed['amount']) { $transformed['payments'] = [[ - 'date' => isset($invoice_data['Last Payment Date']) ? date('Y-m-d', strtotime($invoice_data['Invoice Date'])) : date('Y-m-d'), + 'date' => isset($invoice_data['Last Payment Date']) ? $this->parseDate($invoice_data['Invoice Date']) : date('Y-m-d'), 'amount' => $transformed['amount'] - $transformed['balance'], ]]; } diff --git a/app/Jobs/Ninja/SendReminders.php b/app/Jobs/Ninja/SendReminders.php index c50dabe8641d..f04e6f114538 100644 --- a/app/Jobs/Ninja/SendReminders.php +++ b/app/Jobs/Ninja/SendReminders.php @@ -232,7 +232,6 @@ class SendReminders implements ShouldQueue } $invoice->service()->touchReminder($template)->save(); - // $invoice->save(); } /** diff --git a/app/Listeners/Statement/StatementEmailedActivity.php b/app/Listeners/Statement/StatementEmailedActivity.php new file mode 100644 index 000000000000..0fae3bde51bf --- /dev/null +++ b/app/Listeners/Statement/StatementEmailedActivity.php @@ -0,0 +1,56 @@ +activityRepo = $activityRepo; + } + + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $fields = new stdClass(); + + $user_id = isset($event->event_vars['user_id']) ? $event->event_vars['user_id'] : $event->client->id; + + $fields->user_id = $user_id; + $fields->client_id = $event->client->id; + $fields->notes = $event->end_date; + $fields->company_id = $event->company->id; + $fields->activity_type_id = Activity::EMAIL_STATEMENT; + + $this->activityRepo->save($fields, $event->client, $event->event_vars); + } +} diff --git a/app/Livewire/BillingPortal/Authentication/ClientRegisterService.php b/app/Livewire/BillingPortal/Authentication/ClientRegisterService.php index 1e6a60a6b672..bcb576d70e4c 100644 --- a/app/Livewire/BillingPortal/Authentication/ClientRegisterService.php +++ b/app/Livewire/BillingPortal/Authentication/ClientRegisterService.php @@ -42,18 +42,18 @@ class ClientRegisterService } foreach ($rules as $field => $properties) { - if ($field === 'email') { + if ($field == 'email') { $rules[$field] = array_merge($rules[$field], ['email:rfc', 'max:191', Rule::unique('client_contacts')->where('company_id', $this->company->id)]); } - if ($field === 'current_password' || $field === 'password') { + if ($field == 'current_password' || $field == 'password') { $rules[$field] = array_merge($rules[$field], ['string', 'min:6', 'confirmed']); } } - if ($this->company->settings->client_portal_terms || $this->company->settings->client_portal_privacy_policy) { - $rules['terms'] = ['required']; - } + // if ($this->company->settings->client_portal_terms || $this->company->settings->client_portal_privacy_policy) { + // $rules['terms'] = ['required']; + // } foreach ($this->additional as $field) { if ($field['visible'] ?? true) { diff --git a/app/Livewire/BillingPortal/Authentication/Register.php b/app/Livewire/BillingPortal/Authentication/Register.php index 0bed4bdfda99..6e85cbc62201 100644 --- a/app/Livewire/BillingPortal/Authentication/Register.php +++ b/app/Livewire/BillingPortal/Authentication/Register.php @@ -59,7 +59,6 @@ class Register extends Component public function register(array $data) { - nlog($data); $service = new ClientRegisterService( company: $this->subscription->company, @@ -68,13 +67,8 @@ class Register extends Component $rules = $service->rules(); - nlog($rules); - $data = Validator::make($data, $rules)->validate(); - nlog("validated data"); - nlog($data); - $client = $service->createClient($data); $contact = $service->createClientContact($data, $client); diff --git a/app/Livewire/BillingPortal/Authentication/RegisterOrLogin.php b/app/Livewire/BillingPortal/Authentication/RegisterOrLogin.php index f3d84177507d..4cbecca75207 100644 --- a/app/Livewire/BillingPortal/Authentication/RegisterOrLogin.php +++ b/app/Livewire/BillingPortal/Authentication/RegisterOrLogin.php @@ -202,6 +202,10 @@ class RegisterOrLogin extends Component $this->register_fields = [...collect($this->subscription->company->client_registration_fields ?? [])->toArray()]; + // if ($this->subscription->company->settings->client_portal_terms || $this->subscription->company->settings->client_portal_privacy_policy) { + // $this->register_fields[] = ['key' => 'terms', 'required' => true, 'visible' => 'true']; + // } + $first_gateway = collect($this->subscription->company->company_gateways) ->sortBy('sort_order') ->first(); diff --git a/app/Models/Activity.php b/app/Models/Activity.php index 588d466efdaa..56eb2d490f76 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -258,6 +258,9 @@ class Activity extends StaticModel public const PAYMENT_EMAILED = 138; public const VENDOR_NOTIFICATION_EMAIL = 139; + + public const EMAIL_STATEMENT = 140; + protected $casts = [ 'is_system' => 'boolean', @@ -469,6 +472,8 @@ class Activity extends StaticModel ':adjustment' => $translation = [substr($variable, 1) => [ 'label' => Number::formatMoney($this?->payment?->refunded, $this?->payment?->client ?? $this->company) ?? '', 'hashed_id' => '']], ':ip' => $translation = [ 'ip' => $this->ip ?? ''], ':contact' => $translation = $this->resolveContact(), + ':notes' => $translation = [ 'notes' => $this->notes ?? ''], + default => $translation = [], }; diff --git a/app/Models/Quote.php b/app/Models/Quote.php index cf2d27afe2e2..5a1d73391ab8 100644 --- a/app/Models/Quote.php +++ b/app/Models/Quote.php @@ -164,6 +164,7 @@ class Quote extends BaseModel protected $casts = [ // 'date' => 'date:Y-m-d', + 'tax_data' => 'object', 'due_date' => 'date:Y-m-d', 'partial_due_date' => 'date:Y-m-d', 'line_items' => 'object', diff --git a/app/PaymentDrivers/Authorize/AuthorizeTransaction.php b/app/PaymentDrivers/Authorize/AuthorizeTransaction.php index 84e8b0e60e92..88b6c47d4739 100644 --- a/app/PaymentDrivers/Authorize/AuthorizeTransaction.php +++ b/app/PaymentDrivers/Authorize/AuthorizeTransaction.php @@ -13,15 +13,16 @@ namespace App\PaymentDrivers\Authorize; use App\Models\Invoice; -use App\PaymentDrivers\AuthorizePaymentDriver; use App\Utils\Traits\MakesHash; -use net\authorize\api\contract\v1\CreateTransactionRequest; -use net\authorize\api\contract\v1\ExtendedAmountType; -use net\authorize\api\contract\v1\OpaqueDataType; +use App\PaymentDrivers\Authorize\FDSReview; use net\authorize\api\contract\v1\OrderType; +use App\PaymentDrivers\AuthorizePaymentDriver; use net\authorize\api\contract\v1\PaymentType; use net\authorize\api\contract\v1\SettingType; +use net\authorize\api\contract\v1\OpaqueDataType; +use net\authorize\api\contract\v1\ExtendedAmountType; use net\authorize\api\contract\v1\TransactionRequestType; +use net\authorize\api\contract\v1\CreateTransactionRequest; use net\authorize\api\controller\CreateTransactionController; /** @@ -143,6 +144,12 @@ class AuthorizeTransaction nlog(' Code : '.$tresponse->getMessages()[0]->getCode()); nlog(' Description : '.$tresponse->getMessages()[0]->getDescription()); nlog(print_r($tresponse->getMessages()[0], 1)); + + if($tresponse->getResponseCode() == "4"){ + //notify user that this transaction is being held under FDS review: + FDSReview::dispatch((string)$tresponse->getTransId(), $this->authorize->payment_hash, $this->authorize->company_gateway->company->db); + } + } else { nlog('Transaction Failed '); if ($tresponse->getErrors() != null) { diff --git a/app/PaymentDrivers/Authorize/ChargePaymentProfile.php b/app/PaymentDrivers/Authorize/ChargePaymentProfile.php index 2e242f1326de..551d5b30f3a3 100644 --- a/app/PaymentDrivers/Authorize/ChargePaymentProfile.php +++ b/app/PaymentDrivers/Authorize/ChargePaymentProfile.php @@ -13,14 +13,15 @@ namespace App\PaymentDrivers\Authorize; use App\Models\Invoice; -use App\PaymentDrivers\AuthorizePaymentDriver; use App\Utils\Traits\MakesHash; -use net\authorize\api\contract\v1\CreateTransactionRequest; -use net\authorize\api\contract\v1\CustomerProfilePaymentType; -use net\authorize\api\contract\v1\ExtendedAmountType; +use App\PaymentDrivers\Authorize\FDSReview; use net\authorize\api\contract\v1\OrderType; +use App\PaymentDrivers\AuthorizePaymentDriver; +use net\authorize\api\contract\v1\ExtendedAmountType; use net\authorize\api\contract\v1\PaymentProfileType; use net\authorize\api\contract\v1\TransactionRequestType; +use net\authorize\api\contract\v1\CreateTransactionRequest; +use net\authorize\api\contract\v1\CustomerProfilePaymentType; use net\authorize\api\controller\CreateTransactionController; /** @@ -109,6 +110,12 @@ class ChargePaymentProfile nlog(' Code : '.$tresponse->getMessages()[0]->getCode()); nlog(' Description : '.$tresponse->getMessages()[0]->getDescription()); nlog(print_r($tresponse->getMessages()[0], 1)); + + if($tresponse->getResponseCode() == "4") { + //notify user that this transaction is being held under FDS review: + FDSReview::dispatch((string)$tresponse->getTransId(), $this->authorize?->payment_hash, $this->authorize->company_gateway->company->db); + } + } else { nlog('Transaction Failed '); if ($tresponse->getErrors() != null) { diff --git a/app/PaymentDrivers/Authorize/FDSReview.php b/app/PaymentDrivers/Authorize/FDSReview.php new file mode 100644 index 000000000000..91f7401449a9 --- /dev/null +++ b/app/PaymentDrivers/Authorize/FDSReview.php @@ -0,0 +1,67 @@ +db); + + $company = $this->payment_hash->fee_invoice->company; + + App::setLocale($company->getLocale()); + + $invoices_string = \implode(', ', collect($this->payment_hash->invoices())->pluck('invoice_number')->toArray()) ?: ''; + + $body = "Transaction {$this->transaction_reference} has been held for your review in Auth.net based on your Fraud Detection Settings.\n\n\nWe have marked invoices {$invoices_string} as paid in Invoice Ninja.\n\n\nPlease review this transaction in your auth.net account, and authorize if correct to ensure the transaction is finalized as expected.\n\n\nIf these charges need to be cancelled, you will need to delete the payments that have been created in Invoice Ninja."; + + $mo = new EmailObject(); + $mo->subject = "Transaction {$this->transaction_reference} held for review by auth.net"; + $mo->body = nl2br($body); + $mo->text_body = $body; + $mo->company_key = $company->company_key; + $mo->html_template = 'email.template.generic'; + $mo->to = [new Address($company->owner()->email, $company->owner()->present()->name())]; + + Email::dispatch($mo, $company); + + } + +} diff --git a/app/PaymentDrivers/Stripe/Jobs/PaymentIntentFailureWebhook.php b/app/PaymentDrivers/Stripe/Jobs/PaymentIntentFailureWebhook.php index 2dd7aa420e31..1c5a9b24b5b8 100644 --- a/app/PaymentDrivers/Stripe/Jobs/PaymentIntentFailureWebhook.php +++ b/app/PaymentDrivers/Stripe/Jobs/PaymentIntentFailureWebhook.php @@ -52,25 +52,33 @@ class PaymentIntentFailureWebhook implements ShouldQueue public function handle() { + nlog("payment intent failed"); + MultiDB::findAndSetDbByCompanyKey($this->company_key); + nlog($this->stripe_request); $company = Company::query()->where('company_key', $this->company_key)->first(); foreach ($this->stripe_request as $transaction) { - if (array_key_exists('payment_intent', $transaction)) { - $payment = Payment::query() - ->where('company_id', $company->id) - ->where(function ($query) use ($transaction) { - $query->where('transaction_reference', $transaction['payment_intent']) - ->orWhere('transaction_reference', $transaction['id']); - }) - ->first(); - } else { - $payment = Payment::query() - ->where('company_id', $company->id) - ->where('transaction_reference', $transaction['id']) - ->first(); - } + + nlog($transaction); + + $payment = Payment::query() + ->where('company_id', $company->id) + ->where(function ($query) use ($transaction) { + + if(isset($transaction['payment_intent'])) + $query->where('transaction_reference', $transaction['payment_intent']); + + if(isset($transaction['payment_intent']) && isset($transaction['id'])) + $query->orWhere('transaction_reference', $transaction['id']); + + if(!isset($transaction['payment_intent']) && isset($transaction['id'])) { + $query->where('transaction_reference', $transaction['id']); + } + + }) + ->first(); if ($payment) { $client = $payment->client; diff --git a/app/PaymentDrivers/Stripe/Jobs/PaymentIntentProcessingWebhook.php b/app/PaymentDrivers/Stripe/Jobs/PaymentIntentProcessingWebhook.php index 8c3cb35f3772..c277bb221fd4 100644 --- a/app/PaymentDrivers/Stripe/Jobs/PaymentIntentProcessingWebhook.php +++ b/app/PaymentDrivers/Stripe/Jobs/PaymentIntentProcessingWebhook.php @@ -64,17 +64,28 @@ class PaymentIntentProcessingWebhook implements ShouldQueue $company = Company::query()->where('company_key', $this->company_key)->first(); foreach ($this->stripe_request as $transaction) { - if (array_key_exists('payment_intent', $transaction)) { - $payment = Payment::query() - ->where('company_id', $company->id) - ->where('transaction_reference', $transaction['payment_intent']) - ->first(); - } else { - $payment = Payment::query() - ->where('company_id', $company->id) - ->where('transaction_reference', $transaction['id']) - ->first(); - } + + + $payment = Payment::query() + ->where('company_id', $company->id) + ->where(function ($query) use ($transaction) { + + if(isset($transaction['payment_intent'])) { + $query->where('transaction_reference', $transaction['payment_intent']); + } + + if(isset($transaction['payment_intent']) && isset($transaction['id'])) { + $query->orWhere('transaction_reference', $transaction['id']); + } + + if(!isset($transaction['payment_intent']) && isset($transaction['id'])) { + $query->where('transaction_reference', $transaction['id']); + } + + }) + ->first(); + + if ($payment) { $payment->status_id = Payment::STATUS_PENDING; diff --git a/app/PaymentDrivers/Stripe/Jobs/PaymentIntentWebhook.php b/app/PaymentDrivers/Stripe/Jobs/PaymentIntentWebhook.php index 7aecf4a21702..3cb0d6d403ec 100644 --- a/app/PaymentDrivers/Stripe/Jobs/PaymentIntentWebhook.php +++ b/app/PaymentDrivers/Stripe/Jobs/PaymentIntentWebhook.php @@ -63,17 +63,27 @@ class PaymentIntentWebhook implements ShouldQueue $company = Company::query()->where('company_key', $this->company_key)->first(); foreach ($this->stripe_request as $transaction) { - if (array_key_exists('payment_intent', $transaction)) { - $payment = Payment::query() - ->where('company_id', $company->id) - ->where('transaction_reference', $transaction['payment_intent']) - ->first(); - } else { - $payment = Payment::query() - ->where('company_id', $company->id) - ->where('transaction_reference', $transaction['id']) - ->first(); - } + + $payment = Payment::query() + ->where('company_id', $company->id) + ->where(function ($query) use ($transaction) { + + if(isset($transaction['payment_intent'])) { + $query->where('transaction_reference', $transaction['payment_intent']); + } + + if(isset($transaction['payment_intent']) && isset($transaction['id'])) { + $query->orWhere('transaction_reference', $transaction['id']); + } + + if(!isset($transaction['payment_intent']) && isset($transaction['id'])) { + $query->where('transaction_reference', $transaction['id']); + } + + }) + ->first(); + + if ($payment) { $payment->status_id = Payment::STATUS_COMPLETED; diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index 92f98bb5b669..d5f8e689dad7 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -680,7 +680,7 @@ class StripePaymentDriver extends BaseDriver } if ($request->type === 'payment_intent.processing') { - PaymentIntentProcessingWebhook::dispatch($request->data, $request->company_key, $this->company_gateway->id)->delay(now()->addSeconds(2)); + PaymentIntentProcessingWebhook::dispatch($request->data, $request->company_key, $this->company_gateway->id)->delay(now()->addSeconds(rand(10,12))); return response()->json([], 200); } @@ -692,7 +692,7 @@ class StripePaymentDriver extends BaseDriver } if ($request->type === 'payment_intent.partially_funded') { - PaymentIntentPartiallyFundedWebhook::dispatch($request->data, $request->company_key, $this->company_gateway->id)->delay(now()->addSeconds(rand(5, 10))); + PaymentIntentPartiallyFundedWebhook::dispatch($request->data, $request->company_key, $this->company_gateway->id)->delay(now()->addSeconds(rand(10, 15))); return response()->json([], 200); } @@ -705,20 +705,27 @@ class StripePaymentDriver extends BaseDriver if ($request->type === 'charge.succeeded') { foreach ($request->data as $transaction) { - if (array_key_exists('payment_intent', $transaction) && $transaction['payment_intent']) { - $payment = Payment::query() - // ->where('company_id', $request->getCompany()->id) - ->where(function ($query) use ($transaction) { - $query->where('transaction_reference', $transaction['payment_intent']) - ->orWhere('transaction_reference', $transaction['id']); - }) - ->first(); - } else { - $payment = Payment::query() - // ->where('company_id', $request->getCompany()->id) - ->where('transaction_reference', $transaction['id']) - ->first(); - } + + + $payment = Payment::query() + ->where('company_id', $this->company_gateway->company_id) + ->where(function ($query) use ($transaction) { + + if(isset($transaction['payment_intent'])) { + $query->where('transaction_reference', $transaction['payment_intent']); + } + + if(isset($transaction['payment_intent']) && isset($transaction['id'])) { + $query->orWhere('transaction_reference', $transaction['id']); + } + + if(!isset($transaction['payment_intent']) && isset($transaction['id'])) { + $query->where('transaction_reference', $transaction['id']); + } + + }) + ->first(); + if ($payment) { @@ -745,19 +752,28 @@ class StripePaymentDriver extends BaseDriver ], $this->stripe_connect_auth); if ($charge->captured) { - $payment = false; + + + $payment = Payment::query() + ->where('company_id', $this->company_gateway->company_id) + ->where(function ($query) use ($transaction) { + + if(isset($transaction['payment_intent'])) { + $query->where('transaction_reference', $transaction['payment_intent']); + } + + if(isset($transaction['payment_intent']) && isset($transaction['id'])) { + $query->orWhere('transaction_reference', $transaction['id']); + } + + if(!isset($transaction['payment_intent']) && isset($transaction['id'])) { + $query->where('transaction_reference', $transaction['id']); + } + + }) + ->first(); + - if (isset($transaction['payment_intent'])) { - $payment = Payment::query() - ->where('transaction_reference', $transaction['payment_intent']) - ->where('company_id', $request->getCompany()->id) - ->first(); - } elseif (isset($transaction['id'])) { - $payment = Payment::query() - ->where('transaction_reference', $transaction['id']) - ->where('company_id', $request->getCompany()->id) - ->first(); - } if ($payment) { $payment->status_id = Payment::STATUS_COMPLETED; diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 6c1c1958515a..b7f1a37159e5 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -97,6 +97,7 @@ use App\Events\RecurringQuote\RecurringQuoteWasCreated; use App\Events\RecurringQuote\RecurringQuoteWasDeleted; use App\Events\RecurringQuote\RecurringQuoteWasRestored; use App\Events\RecurringQuote\RecurringQuoteWasUpdated; +use App\Events\Statement\StatementWasEmailed; use App\Events\Subscription\SubscriptionWasArchived; use App\Events\Subscription\SubscriptionWasCreated; use App\Events\Subscription\SubscriptionWasDeleted; @@ -222,6 +223,7 @@ use App\Listeners\RecurringQuote\RecurringQuoteDeletedActivity; use App\Listeners\RecurringQuote\RecurringQuoteRestoredActivity; use App\Listeners\RecurringQuote\UpdateRecurringQuoteActivity; use App\Listeners\SendVerificationNotification; +use App\Listeners\Statement\StatementEmailedActivity; use App\Listeners\User\ArchivedUserActivity; use App\Listeners\User\CreatedUserActivity; use App\Listeners\User\DeletedUserActivity; @@ -577,6 +579,9 @@ class EventServiceProvider extends ServiceProvider RecurringInvoiceWasRestored::class => [ RecurringInvoiceRestoredActivity::class, ], + StatementWasEmailed::class => [ + StatementEmailedActivity::class, + ], TaskWasCreated::class => [ CreatedTaskActivity::class, ], diff --git a/app/Services/Client/ClientService.php b/app/Services/Client/ClientService.php index 31e6cc524f7f..b792d44bf35f 100644 --- a/app/Services/Client/ClientService.php +++ b/app/Services/Client/ClientService.php @@ -11,6 +11,7 @@ namespace App\Services\Client; +use App\Utils\Ninja; use App\Utils\Number; use App\Models\Client; use App\Models\Credit; @@ -23,6 +24,7 @@ use App\Services\Email\EmailObject; use App\Utils\Traits\GeneratesCounter; use Illuminate\Mail\Mailables\Address; use Illuminate\Database\QueryException; +use App\Events\Statement\StatementWasEmailed; class ClientService { @@ -275,6 +277,9 @@ class ClientService $email_object = $this->buildStatementMailableData($pdf); Email::dispatch($email_object, $this->client->company); + + event(new StatementWasEmailed($this->client, $this->client->company, $this->client_end_date, Ninja::eventVars())); + } /** @@ -307,8 +312,8 @@ class ClientService $email_object->attachments = [['file' => base64_encode($pdf), 'name' => ctrans('texts.statement') . ".pdf"]]; $email_object->client_id = $this->client->id; $email_object->entity_class = Invoice::class; - $email_object->entity_id = $invoice->id ?? null; - $email_object->invitation_id = $invoice->invitations->first()->id ?? null; + $email_object->entity_id = $invoice?->id ?? null; + $email_object->invitation_id = $invoice?->invitations?->first()?->id ?? null; $email_object->email_template_subject = 'email_subject_statement'; $email_object->email_template_body = 'email_template_statement'; $email_object->variables = [ diff --git a/app/Services/Scheduler/EmailStatementService.php b/app/Services/Scheduler/EmailStatementService.php index eb4e288f2e60..1111090a8c07 100644 --- a/app/Services/Scheduler/EmailStatementService.php +++ b/app/Services/Scheduler/EmailStatementService.php @@ -44,6 +44,8 @@ class EmailStatementService $query->cursor() ->each(function ($_client) { + + /**@var \App\Models\Client $_client */ $this->client = $_client; //work out the date range diff --git a/app/Utils/Traits/CleanLineItems.php b/app/Utils/Traits/CleanLineItems.php index a2457c4056b9..9d20511e5770 100644 --- a/app/Utils/Traits/CleanLineItems.php +++ b/app/Utils/Traits/CleanLineItems.php @@ -90,4 +90,18 @@ trait CleanLineItems return $item; } + + private function entityTotalAmount($items) + { + $total = 0; + + foreach($items as $item) + { + $total += ($item['cost'] * $item['quantity']); + } + + nlog($total); + + return $total; + } } diff --git a/config/ninja.php b/config/ninja.php index 1cc85778fe09..c2b2ee858378 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -17,8 +17,8 @@ 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.8.53'), - 'app_tag' => env('APP_TAG', '5.8.53'), + 'app_version' => env('APP_VERSION', '5.8.54'), + 'app_tag' => env('APP_TAG', '5.8.54'), 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', false), diff --git a/lang/ar/texts.php b/lang/ar/texts.php index e9f2e6bd7203..0c56c48f4e74 100644 --- a/lang/ar/texts.php +++ b/lang/ar/texts.php @@ -4010,7 +4010,7 @@ $lang = array( 'user_detached' => 'فصل المستخدم عن الشركة', 'create_webhook_failure' => 'فشل إنشاء Webhook', 'payment_message_extended' => 'شكرًا لك على دفعك لـ :amount مقابل :invoice', - 'online_payments_minimum_note' => 'ملاحظة: يتم دعم المدفوعات عبر الإنترنت فقط إذا كان المبلغ أكبر من دولار واحد أو ما يعادله بالعملة.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'لم يتم العثور على رمز الدفع ، يرجى المحاولة مرة أخرى. إذا استمرت المشكلة ، فحاول استخدام طريقة دفع أخرى', 'vendor_address1' => 'شارع البائع', 'vendor_address2' => 'بائع شقة / جناح', @@ -5278,6 +5278,9 @@ $lang = array( 'rappen_rounding_help' => 'جولة المبلغ إلى 5 سنتات', 'assign_group' => 'تعيين المجموعة', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/ca/texts.php b/lang/ca/texts.php index 5c5438884a87..8b287895b718 100644 --- a/lang/ca/texts.php +++ b/lang/ca/texts.php @@ -4029,7 +4029,7 @@ $lang = array( 'user_detached' => 'User detached from company', 'create_webhook_failure' => 'Failed to create Webhook', 'payment_message_extended' => 'Thank you for your payment of :amount for :invoice', - 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is bigger than $1 or currency equivalent.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Payment token not found, please try again. If an issue still persist, try with another payment method', 'vendor_address1' => 'Vendor Street', 'vendor_address2' => 'Vendor Apt/Suite', @@ -5297,6 +5297,9 @@ $lang = array( 'rappen_rounding_help' => 'Import rodó a 5 cèntims', 'assign_group' => 'Assigna un grup', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/da/texts.php b/lang/da/texts.php index 7b3c4fa0fb24..a3e2c75d7bd9 100644 --- a/lang/da/texts.php +++ b/lang/da/texts.php @@ -4028,7 +4028,7 @@ $lang = array( 'user_detached' => 'Bruger løsrevet fra selskabet', 'create_webhook_failure' => 'Opret Webhook mislykkedes', 'payment_message_extended' => 'Tak for din Betaling på :amount for :invoice', - 'online_payments_minimum_note' => 'Bemærk : Online Betalinger understøttes kun, hvis Beløb er større end $1 eller tilsvarende i valuta.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Betaling blev ikke fundet, prøv venligst igen. Hvis et problem stadig fortsætter, kan du prøve med en anden Betaling', 'vendor_address1' => 'Sælger Gade', 'vendor_address2' => 'Sælger Apt/Suite', @@ -5296,6 +5296,9 @@ $lang = array( 'rappen_rounding_help' => 'Rund Beløb til 5 øre', 'assign_group' => 'Tildel gruppe', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/de/texts.php b/lang/de/texts.php index 1c1a2dadeb13..98da0ee725bf 100644 --- a/lang/de/texts.php +++ b/lang/de/texts.php @@ -4031,7 +4031,7 @@ https://invoiceninja.github.io/docs/migration/#troubleshooting', 'user_detached' => 'Nutzer wurden vom Unternehmen entkoppelt', 'create_webhook_failure' => 'Webhook konnte nicht erstellt werden', 'payment_message_extended' => 'Vielen Dank für Ihre Zahlung von :amount für die Rechnung :invoice', - 'online_payments_minimum_note' => 'Hinweis: Online-Zahlungen werden nur unterstützt, wenn der Betrag größer als 1€ oder der entsprechende Währungsbetrag ist.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Zahlungstoken nicht gefunden, bitte versuchen Sie es erneut. Wenn das Problem weiterhin besteht, versuchen Sie es mit einer anderen Zahlungsmethode', 'vendor_address1' => 'Straße Lieferant', 'vendor_address2' => 'Lieferant Apt/Suite', @@ -5301,6 +5301,9 @@ Leistungsempfängers', 'rappen_rounding_help' => 'Betrag auf 5 Cent aufrunden', 'assign_group' => 'Gruppe zuweisen', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/en/texts.php b/lang/en/texts.php index ddaefd601758..ffc9c157cc7a 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5300,6 +5300,10 @@ $lang = array( 'local_domain_help' => 'EHLO domain (optional)', 'port_help' => 'ie. 25,587,465', 'host_help' => 'ie. smtp.gmail.com', + 'always_show_required_fields' => 'Allows show required fields form', + 'always_show_required_fields_help' => 'Displays the required fields form always at checkout', + 'advanced_cards' => 'Advanced Cards', + 'activity_140' => 'Statement sent to :client', ); return $lang; diff --git a/lang/es/texts.php b/lang/es/texts.php index 488ef1cea6f9..c19863a7f439 100644 --- a/lang/es/texts.php +++ b/lang/es/texts.php @@ -4028,7 +4028,7 @@ $lang = array( 'user_detached' => 'Usuario desvinculado de la empresa', 'create_webhook_failure' => 'No se pudo crear el webhook', 'payment_message_extended' => 'Gracias por su pago de :amount por :invoice', - 'online_payments_minimum_note' => 'Nota: Los pagos en línea solo se admiten si el monto es superior a $ 1 o su equivalente en moneda.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'No se encontró el token de pago, inténtelo de nuevo. Si el problema persiste, intente con otro método de pago', 'vendor_address1' => 'Calle del vendedor', 'vendor_address2' => 'Proveedor Apt/Suite', @@ -5296,6 +5296,9 @@ $lang = array( 'rappen_rounding_help' => 'Monto redondo a 5 centavos', 'assign_group' => 'Asignar grupo', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/es_ES/texts.php b/lang/es_ES/texts.php index 153050804d9f..1ceaaaf83c62 100644 --- a/lang/es_ES/texts.php +++ b/lang/es_ES/texts.php @@ -2193,7 +2193,7 @@ Una vez que tenga los montos, vuelva a esta página de métodos de pago y haga c 'mailgun_private_key' => 'Mailgun Private Key', 'brevo_domain' => 'Dominio Brevo', 'brevo_private_key' => 'Clave privada de Brevo', - 'send_test_email' => 'Send Test Email', + 'send_test_email' => 'Enviar correo electrónico de prueba', 'select_label' => 'Seleccionar etiqueta', 'label' => 'Etiqueta', 'service' => 'Servicio', @@ -4025,7 +4025,7 @@ Una vez que tenga los montos, vuelva a esta página de métodos de pago y haga c 'user_detached' => 'Usuario desligado de la compañía', 'create_webhook_failure' => 'Fallo al crear Webhook', 'payment_message_extended' => 'Gracias por su pago de :amount para :invoice', - 'online_payments_minimum_note' => 'Nota: Los pagos online están soportados si la cantidad es mayor que $1 o moneda equivalente.', + 'online_payments_minimum_note' => 'Nota: Los pagos en línea solo se admiten si el importe es superior a 1 € o moneda equivalente.', 'payment_token_not_found' => 'No se ha encontrado el token de pago, inténtelo de nuevo. Si el problema persiste, inténtelo con otro método de pago', 'vendor_address1' => 'Calle de Proveedor', 'vendor_address2' => 'Bloq/Pta del Proveedor', @@ -4166,7 +4166,7 @@ Una vez que tenga los montos, vuelva a esta página de métodos de pago y haga c 'one_time_purchases' => 'Compras únicas', 'recurring_purchases' => 'Pagos recurrentes', 'you_might_be_interested_in_following' => 'Puede que te interese lo siguiente', - 'quotes_with_status_sent_can_be_approved' => 'Only quotes with "Sent" status can be approved. Expired quotes cannot be approved.', + 'quotes_with_status_sent_can_be_approved' => 'Sólo se pueden aprobar presupuestos con estado "Enviado". Los presupuestos vencidos no se pueden aprobar.', 'no_quotes_available_for_download' => 'No hay presupuestos disponibles para descargar.', 'copyright' => 'Derechos de autor', 'user_created_user' => ':user creó :created_user a las :time', @@ -5292,8 +5292,11 @@ De lo contrario, este campo deberá dejarse en blanco.', 'flutter_web_warning' => 'Recomendamos utilizar la nueva aplicación web o la aplicación de escritorio para obtener el mejor rendimiento.', 'rappen_rounding' => 'Redondeo de rappen', 'rappen_rounding_help' => 'Cantidad redonda a 5 centimos', - 'assign_group' => 'Assign group', - 'paypal_advanced_cards' => 'Advanced Card Payments', + 'assign_group' => 'Asignar grupo', + 'paypal_advanced_cards' => 'Pagos avanzados con tarjeta', + 'local_domain_help' => 'Dominio EHLO (opcional)', + 'port_help' => 'Ej. 25.587.465', + 'host_help' => 'Ej. smtp.gmail.com', ); return $lang; diff --git a/lang/fr/texts.php b/lang/fr/texts.php index 16d27ea6d31e..5ac3f1ba58ac 100644 --- a/lang/fr/texts.php +++ b/lang/fr/texts.php @@ -4029,7 +4029,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'user_detached' => 'Utilisateur détaché de l\'entreprise', 'create_webhook_failure' => 'Échec de la création du Webhook', 'payment_message_extended' => 'Merci pour votre paiement de :amount pour :invoice', - 'online_payments_minimum_note' => 'Remarque : Les paiements en ligne ne sont pris en charge que si le montant est supérieur à 1 $ ou l\'équivalent en devise.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Le jeton de paiement est introuvable. Veuillez essayer de nouveau. Si le problème persiste, essayez avec un autre mode de paiement', 'vendor_address1' => 'Rue du fournisseur', 'vendor_address2' => 'Appt/Bâtiment du fournisseur', @@ -5297,6 +5297,9 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'rappen_rounding_help' => 'Montant rond à 5 centimes', 'assign_group' => 'Attribuer un groupe', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/fr_CA/texts.php b/lang/fr_CA/texts.php index 013f1710570a..adecee4bb1b7 100644 --- a/lang/fr_CA/texts.php +++ b/lang/fr_CA/texts.php @@ -4026,7 +4026,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'user_detached' => 'L\'utilisateur a été détaché de l\'entreprise', 'create_webhook_failure' => 'Création Webhook impossible', 'payment_message_extended' => 'Merci pour votre paiement d\'un montant de :amount', - 'online_payments_minimum_note' => 'Note: Les paiements en ligne sont acceptés seulement si le montant est plus élevé que 1$ ou en devise équivalente.', + 'online_payments_minimum_note' => 'Note: Les paiements en ligne sont possibles seulement si le montant est supérieur à 1$ ou l\'équivalent en devise.', 'payment_token_not_found' => 'Le jeton de paiement est introuvable. Veuillez essayer de nouveau. Si le problème persiste, essayez avec un autre mode de paiement', 'vendor_address1' => 'Rue du fournisseur', 'vendor_address2' => 'App du fournisseur', @@ -5294,6 +5294,9 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'rappen_rounding_help' => 'Arrondir au 5 cents', 'assign_group' => 'Assigner un groupe', 'paypal_advanced_cards' => 'Paiements avancés pour carte', + 'local_domain_help' => 'Domaine EHLO (facultatif)', + 'port_help' => 'ex. 25,587,465', + 'host_help' => 'ex. smtp.gmail.com', ); return $lang; diff --git a/lang/fr_CH/texts.php b/lang/fr_CH/texts.php index 748f848f6b27..3ebbd72abf14 100644 --- a/lang/fr_CH/texts.php +++ b/lang/fr_CH/texts.php @@ -4026,7 +4026,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'user_detached' => 'L\'utilisateur a été détaché de l\'entreprise', 'create_webhook_failure' => 'Création Webhook impossible', 'payment_message_extended' => 'Merci pour votre paiement d\'un montant de :amount', - 'online_payments_minimum_note' => 'Note: Les paiements en ligne sont acceptés seulement si le montant est plus élevé que 1$ ou en devise équivalente.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Le jeton de paiement est introuvable. Veuillez essayer de nouveau. Si le problème persiste, essayez avec un autre mode de paiement', 'vendor_address1' => 'Rue du fournisseur', 'vendor_address2' => 'App du fournisseur', @@ -5294,6 +5294,9 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'rappen_rounding_help' => 'Montant rond à 5 centimes', 'assign_group' => 'Attribuer un groupe', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/he/texts.php b/lang/he/texts.php index 31c19c894186..1fcbacd8e260 100644 --- a/lang/he/texts.php +++ b/lang/he/texts.php @@ -4027,7 +4027,7 @@ $lang = array( 'user_detached' => 'משתמש מנותק מהחברה', 'create_webhook_failure' => 'יצירת Webhook נכשלה', 'payment_message_extended' => 'תודה על התשלום בסך :amount עבור :invoice', - 'online_payments_minimum_note' => 'הערה: תשלומים מקוונים נתמכים רק אם הסכום גדול מ-$1 או שווה ערך במטבע.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'אסימון תשלום לא נמצא, אנא נסה שוב. אם הבעיה עדיין נמשכת, נסה עם אמצעי תשלום אחר', 'vendor_address1' => 'רחוב הספקים', 'vendor_address2' => 'דירת ספק/סוויטה', @@ -5295,6 +5295,9 @@ $lang = array( 'rappen_rounding_help' => 'סכום עגול עד 5 סנט', 'assign_group' => 'הקצה קבוצה', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/hu/texts.php b/lang/hu/texts.php index dea3c16eedfe..dc6a2ae95cf9 100644 --- a/lang/hu/texts.php +++ b/lang/hu/texts.php @@ -4013,7 +4013,7 @@ adva :date', 'user_detached' => 'Felhasználó leválasztva', 'create_webhook_failure' => 'Webhook létrehozása sikertelen', 'payment_message_extended' => 'Fizetési üzenet kiterjesztve', - 'online_payments_minimum_note' => 'Online fizetések minimális megjegyzése', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Fizetési token nem található', 'vendor_address1' => 'Szállító címe 1', 'vendor_address2' => 'Szállító címe 2', @@ -5281,6 +5281,9 @@ adva :date', 'rappen_rounding_help' => 'Kerek összeg 5 cent', 'assign_group' => 'Csoport hozzárendelése', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/it/texts.php b/lang/it/texts.php index 73a68976480f..3be580a43d24 100644 --- a/lang/it/texts.php +++ b/lang/it/texts.php @@ -4020,7 +4020,7 @@ $lang = array( 'user_detached' => 'Utente separato dall\'azienda', 'create_webhook_failure' => 'Impossibile creare il webhook', 'payment_message_extended' => 'Grazie per il pagamento di :amount per :invoice', - 'online_payments_minimum_note' => 'Nota: i pagamenti online sono supportati solo se l'importo è superiore a $ 1 o equivalente in valuta.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Token di pagamento non trovato, riprova. Se il problema persiste, prova con un altro metodo di pagamento', 'vendor_address1' => 'Via Fornitore', 'vendor_address2' => 'Scala/Appartamento Fornitore', @@ -5288,6 +5288,9 @@ $lang = array( 'rappen_rounding_help' => 'Ammontare tondo a 5 centesimi', 'assign_group' => 'Assegna gruppo', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/ja/texts.php b/lang/ja/texts.php index c51257e85de0..9f046c23ceb4 100644 --- a/lang/ja/texts.php +++ b/lang/ja/texts.php @@ -2197,7 +2197,7 @@ $lang = array( 'mailgun_private_key' => 'Mailgun Private Key', 'brevo_domain' => 'Brevo Domain', 'brevo_private_key' => 'Brevo Private Key', - 'send_test_email' => 'Send test email', + 'send_test_email' => 'Send Test Email', 'select_label' => 'Select Label', 'label' => 'Label', 'service' => 'Service', @@ -4029,7 +4029,7 @@ $lang = array( 'user_detached' => 'User detached from company', 'create_webhook_failure' => 'Failed to create Webhook', 'payment_message_extended' => ':invoice に対して :amount をお支払いいただきありがとうございます。', - 'online_payments_minimum_note' => '注: オンラインでの支払いは、金額が 1 ドルまたは同等の通貨を超える場合にのみサポートされます。', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Payment token not found, please try again. If an issue still persist, try with another payment method', 'vendor_address1' => 'Vendor Street', 'vendor_address2' => 'Vendor Apt/Suite', @@ -4170,7 +4170,7 @@ $lang = array( 'one_time_purchases' => 'One time purchases', 'recurring_purchases' => 'Recurring purchases', 'you_might_be_interested_in_following' => 'You might be interested in the following', - 'quotes_with_status_sent_can_be_approved' => 'Only quotes with "Sent" status can be approved.', + 'quotes_with_status_sent_can_be_approved' => 'Only quotes with "Sent" status can be approved. Expired quotes cannot be approved.', 'no_quotes_available_for_download' => 'No quotes available for download.', 'copyright' => 'Copyright', 'user_created_user' => ':user は :created_user を :time に作成しました', @@ -5295,6 +5295,11 @@ $lang = array( 'flutter_web_warning' => 'We recommend using the new web app or the desktop app for the best performance', 'rappen_rounding' => 'Rappen Rounding', 'rappen_rounding_help' => 'Round amount to 5 cents', + 'assign_group' => 'Assign group', + 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/km_KH/texts.php b/lang/km_KH/texts.php index 2e92ffd91ce8..9733863f301a 100644 --- a/lang/km_KH/texts.php +++ b/lang/km_KH/texts.php @@ -4009,7 +4009,7 @@ $lang = array( 'user_detached' => 'អ្នកប្រើប្រាស់ត្រូវបានផ្តាច់ចេញពីក្រុមហ៊ុន', 'create_webhook_failure' => 'បរាជ័យក្នុងការបង្កើត Webhook', 'payment_message_extended' => 'សូមអរគុណចំពោះការបង់ប្រាក់របស់អ្នក :amount សម្រាប់ :invoice', - 'online_payments_minimum_note' => 'ចំណាំ៖ ការទូទាត់តាមអ៊ីនធឺណិតត្រូវបានគាំទ្រលុះត្រាតែចំនួនទឹកប្រាក់ធំជាង $1 ឬសមមូលរូបិយប័ណ្ណ។', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'រកមិនឃើញនិមិត្តសញ្ញាបង់ប្រាក់ទេ សូមព្យាយាមម្តងទៀត។ ប្រសិនបើបញ្ហានៅតែកើតមាន សូមសាកល្បងជាមួយវិធីបង់ប្រាក់ផ្សេងទៀត។', 'vendor_address1' => 'ផ្លូវអ្នកលក់', 'vendor_address2' => 'អ្នកលក់ Apt/Suite', @@ -5277,6 +5277,9 @@ $lang = array( 'rappen_rounding_help' => 'ចំនួនទឹកប្រាក់ជុំដល់ 5 សេន', 'assign_group' => 'ចាត់តាំងក្រុម', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/lo_LA/texts.php b/lang/lo_LA/texts.php index a2c6a5da833a..5aecc2bd0cc8 100644 --- a/lang/lo_LA/texts.php +++ b/lang/lo_LA/texts.php @@ -4029,7 +4029,7 @@ $lang = array( 'user_detached' => 'ຜູ້ໃຊ້ຖືກແຍກອອກຈາກບໍລິສັດ', 'create_webhook_failure' => 'ລົ້ມເຫລວໃນການສ້າງ Webhook', 'payment_message_extended' => 'ຂໍຂອບໃຈສຳລັບການຈ່າຍເງິນ:ຈຳນວນເງິນ:ໃບແຈ້ງໜີ້', - 'online_payments_minimum_note' => 'ໝາຍເຫດ: ການຈ່າຍເງິນອອນລາຍແມ່ນຮອງຮັບໄດ້ພຽງແຕ່ຖ້າຈຳນວນເງິນໃຫຍ່ກວ່າ $1 ຫຼື ທຽບເທົ່າສະກຸນເງິນເທົ່ານັ້ນ.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'ບໍ່ພົບໂທເຄັນການຈ່າຍເງິນ, ກະລຸນາລອງໃໝ່ອີກຄັ້ງ. ຖ້າບັນຫາຍັງຄົງຢູ່, ໃຫ້ລອງໃຊ້ວິທີຈ່າຍເງິນອື່ນ', 'vendor_address1' => 'ຖະໜົນຜູ້ຂາຍ', 'vendor_address2' => 'ຜູ້ຂາຍ Apt/Suite', @@ -5297,6 +5297,9 @@ $lang = array( 'rappen_rounding_help' => 'ຈໍານວນຮອບເປັນ 5 ເຊັນ', 'assign_group' => 'ກຳນົດກຸ່ມ', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/nl/texts.php b/lang/nl/texts.php index d28699596fdf..f95a12f85c37 100644 --- a/lang/nl/texts.php +++ b/lang/nl/texts.php @@ -4026,7 +4026,7 @@ Kom terug naar deze betalingsmethode pagina zodra u de bedragen heeft ontvangen 'user_detached' => 'Gebruiker losgekoppeld van bedrijf', 'create_webhook_failure' => 'Maken van webhook is mislukt', 'payment_message_extended' => 'Bedankt voor uw betaling van :amount voor :invoice', - 'online_payments_minimum_note' => 'Opmerking: Online betalingen worden alleen ondersteund als het bedrag groter is dan € 1 of het equivalent in een andere valuta.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Betalingstoken niet gevonden. Probeer het opnieuw. Als het probleem zich blijft voordoen, probeer het dan met een andere betaalmethode', 'vendor_address1' => 'Leverancier straatnaam', 'vendor_address2' => 'Leverancier Apt / Suite', @@ -5297,6 +5297,9 @@ Email: :email
', 'rappen_rounding_help' => 'Rond het bedrag af op 5 cent', 'assign_group' => 'Groep toewijzen', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/pt_BR/texts.php b/lang/pt_BR/texts.php index 077fbe4bcee6..2496de3271f1 100644 --- a/lang/pt_BR/texts.php +++ b/lang/pt_BR/texts.php @@ -4026,7 +4026,7 @@ Quando tiver as quantias, volte a esta página de formas de pagamento e clique " 'user_detached' => 'Usuário desconectado da empresa', 'create_webhook_failure' => 'Falha ao criar Webhook', 'payment_message_extended' => 'Obrigado pelo seu pagamento de :amount por :invoice', - 'online_payments_minimum_note' => 'Nota: Os pagamentos on-line são suportados apenas se o valor for superior a US$ 1 ou o equivalente em moeda.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Token de pagamento não encontrado. Tente novamente. Se o problema persistir, tente outra forma de pagamento', 'vendor_address1' => 'Rua do Vendedor', 'vendor_address2' => 'Apartamento/Suíte do Vendedor', @@ -5294,6 +5294,9 @@ Quando tiver as quantias, volte a esta página de formas de pagamento e clique " 'rappen_rounding_help' => 'Montante redondo para 5 centavos', 'assign_group' => 'Atribuir grupo', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/pt_PT/texts.php b/lang/pt_PT/texts.php index 116e3887dd05..17218c9b85ad 100644 --- a/lang/pt_PT/texts.php +++ b/lang/pt_PT/texts.php @@ -4028,7 +4028,7 @@ debitar da sua conta de acordo com essas instruções. Está elegível a um reem 'user_detached' => 'Utilizador não vinculado à empresa', 'create_webhook_failure' => 'Falha ao criar Webhook', 'payment_message_extended' => 'Obrigado pelo pagamento de :amount para :invoice', - 'online_payments_minimum_note' => 'Nota: Pagamentos online estão disponíveis se a quantia for superior a 1$ ou ao equivalente na moeda utilizada.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Token de pagamento não encontrada, por favor tente novamente. Se este erro persistir, tente outro método de pagamento', 'vendor_address1' => 'Morada Fornecedor', 'vendor_address2' => 'Andar / Fração Fornecedor', @@ -5297,6 +5297,9 @@ O envio de E-mails foi suspenso. Será retomado às 23:00 UTC.', 'rappen_rounding_help' => 'Montante redondo para 5 centavos', 'assign_group' => 'Atribuir grupo', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/ro/texts.php b/lang/ro/texts.php index 4b62393e375e..994490e1f6ce 100644 --- a/lang/ro/texts.php +++ b/lang/ro/texts.php @@ -4030,7 +4030,7 @@ Odată ce sumele au ajuns la dumneavoastră, reveniți la pagina cu metode de pl 'user_detached' => 'Utilizatorul s-a detașat de companie', 'create_webhook_failure' => 'Webhook nu a putut fi creat', 'payment_message_extended' => 'Mulțumim că ați efectuat plata în valoare de :amount pentru :invoice', - 'online_payments_minimum_note' => 'Notă: Plățile online pot fi efectuate doar dacă suma depășește $1 sau echivalentul în valută.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Token-ul de plată nu a putut fi găsit. Încercați din nou. Dacă nu funcționează, încercați o altă metodă de plată', 'vendor_address1' => 'Stradă furnizor', 'vendor_address2' => 'Apartament furnizor', @@ -5298,6 +5298,9 @@ Odată ce sumele au ajuns la dumneavoastră, reveniți la pagina cu metode de pl 'rappen_rounding_help' => 'Suma rotundă la 5 cenți', 'assign_group' => 'Atribuiți grup', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/sk/texts.php b/lang/sk/texts.php index c2ded8d8e435..fd5bb9ac0fb6 100644 --- a/lang/sk/texts.php +++ b/lang/sk/texts.php @@ -2847,7 +2847,7 @@ $lang = array( 'reminder1' => 'Prvá Upomienka', 'reminder2' => 'Druhá Upomienka', 'reminder3' => 'Tretia Upomienka', - 'send' => 'Odoslané', + 'send' => 'Odoslať', 'auto_billing' => 'Automatické účtovanie', 'button' => 'Tlačidlo', 'more' => 'VIac', @@ -4016,7 +4016,7 @@ $lang = array( 'user_detached' => 'Používateľ je oddelený od spoločnosti', 'create_webhook_failure' => 'Nepodarilo sa vytvoriť webhook', 'payment_message_extended' => 'Ďakujeme za platbu vo výške :amount za :invoice', - 'online_payments_minimum_note' => 'Poznámka: Online platby sú podporované iba vtedy, ak je suma vyššia ako 1 $ alebo ekvivalent v inej mene.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Platobný token sa nenašiel, skúste to znova. Ak problém stále pretrváva, skúste použiť iný spôsob platby ', 'vendor_address1' => 'Ulica predajcu', 'vendor_address2' => 'Apartmán/byt dodávateľa', @@ -4223,7 +4223,7 @@ $lang = array( 'payment_type_Bancontact' => 'Zákaz kontaktu', 'payment_type_BECS' => 'BECS', 'payment_type_ACSS' => 'ACSS', - 'gross_line_total' => 'Hrubý riadok celkom', + 'gross_line_total' => 'Celková suma brutto', 'lang_Slovak' => 'Slovensky', 'normal' => 'Normálne', 'large' => 'Veľké', @@ -5284,6 +5284,9 @@ $lang = array( 'rappen_rounding_help' => 'Okrúhla suma do 5 centov', 'assign_group' => 'Priradiť skupinu', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/sr/texts.php b/lang/sr/texts.php index 48302c06ae09..616b5db0f574 100644 --- a/lang/sr/texts.php +++ b/lang/sr/texts.php @@ -4029,7 +4029,7 @@ Kada budete imali iznose, vratite se na ovu stranicu sa načinima plaćanja i k 'user_detached' => 'Korisnik je odvojen od kompanije', 'create_webhook_failure' => 'Neuspešno kreiranje Webhook-a', 'payment_message_extended' => 'Hvala vam na vašoj uplati od :amount za :invoice', - 'online_payments_minimum_note' => 'Napomena: onlajn plaćanja su podržana samo ako je iznos veći od 1 USD ili ekvivalentne valute.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Token za plaćanje nije pronađen, pokušajte ponovo. Ako problem i dalje postoji, pokušajte sa drugim načinom plaćanja ', 'vendor_address1' => 'Ulica dobavljača', 'vendor_address2' => 'Stan/apartman dobavljača', @@ -5297,6 +5297,9 @@ Kada budete imali iznose, vratite se na ovu stranicu sa načinima plaćanja i k 'rappen_rounding_help' => 'Round amount to 5 cents', 'assign_group' => 'Assign group', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/sv/texts.php b/lang/sv/texts.php index 2405b3adaf77..f5440b6f0bf2 100644 --- a/lang/sv/texts.php +++ b/lang/sv/texts.php @@ -4037,7 +4037,7 @@ Den här funktionen kräver att en produkt skapas och en betalningsgateway är k 'user_detached' => 'Användaren har kopplats bort från företaget', 'create_webhook_failure' => 'Det gick inte att skapa Webhook', 'payment_message_extended' => 'Tack för din betalning på :amount för :invoice', - 'online_payments_minimum_note' => 'Notera: Online betalningar stöds endast om beloppet är större än 10:- eller motsvarande valuta.', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => 'Betalningstoken hittades inte. Försök igen. Om problemet fortfarande kvarstår kan du prova med en annan betalningsmetod', 'vendor_address1' => 'Leverantörsadress', 'vendor_address2' => 'Leverantörsadress 2', @@ -5305,6 +5305,9 @@ Den här funktionen kräver att en produkt skapas och en betalningsgateway är k 'rappen_rounding_help' => 'Round amount to 5 cents', 'assign_group' => 'Assign group', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/lang/zh_TW/texts.php b/lang/zh_TW/texts.php index aab264a09ed0..c81ce606f421 100644 --- a/lang/zh_TW/texts.php +++ b/lang/zh_TW/texts.php @@ -4029,7 +4029,7 @@ $lang = array( 'user_detached' => '用戶脫離公司', 'create_webhook_failure' => '建立 Webhook 失敗', 'payment_message_extended' => '感謝您為:amount支付:invoice', - 'online_payments_minimum_note' => '注意:僅當金額大於 1 美元或等值貨幣時才支援線上付款。', + 'online_payments_minimum_note' => 'Note: Online payments are supported only if amount is larger than $1 or currency equivalent.', 'payment_token_not_found' => '未找到支付令牌,請重試。如果問題仍然存在,請嘗試使用其他付款方式', 'vendor_address1' => '供應商街', 'vendor_address2' => '供應商 公寓/套房', @@ -5297,6 +5297,9 @@ $lang = array( 'rappen_rounding_help' => '金額為 5 美分', 'assign_group' => '分配群組', 'paypal_advanced_cards' => 'Advanced Card Payments', + 'local_domain_help' => 'EHLO domain (optional)', + 'port_help' => 'ie. 25,587,465', + 'host_help' => 'ie. smtp.gmail.com', ); return $lang; diff --git a/public/build/assets/app-042e859e.js b/public/build/assets/app-042e859e.js deleted file mode 100644 index 64e1f2bbeb1f..000000000000 --- a/public/build/assets/app-042e859e.js +++ /dev/null @@ -1,109 +0,0 @@ -import{A as pl}from"./index-08e160a7.js";import{c as Ht,g as hl}from"./_commonjsHelpers-725317a4.js";var gl={visa:{niceType:"Visa",type:"visa",patterns:[4],gaps:[4,8,12],lengths:[16,18,19],code:{name:"CVV",size:3}},mastercard:{niceType:"Mastercard",type:"mastercard",patterns:[[51,55],[2221,2229],[223,229],[23,26],[270,271],2720],gaps:[4,8,12],lengths:[16],code:{name:"CVC",size:3}},"american-express":{niceType:"American Express",type:"american-express",patterns:[34,37],gaps:[4,10],lengths:[15],code:{name:"CID",size:4}},"diners-club":{niceType:"Diners Club",type:"diners-club",patterns:[[300,305],36,38,39],gaps:[4,10],lengths:[14,16,19],code:{name:"CVV",size:3}},discover:{niceType:"Discover",type:"discover",patterns:[6011,[644,649],65],gaps:[4,8,12],lengths:[16,19],code:{name:"CID",size:3}},jcb:{niceType:"JCB",type:"jcb",patterns:[2131,1800,[3528,3589]],gaps:[4,8,12],lengths:[16,17,18,19],code:{name:"CVV",size:3}},unionpay:{niceType:"UnionPay",type:"unionpay",patterns:[620,[624,626],[62100,62182],[62184,62187],[62185,62197],[62200,62205],[622010,622999],622018,[622019,622999],[62207,62209],[622126,622925],[623,626],6270,6272,6276,[627700,627779],[627781,627799],[6282,6289],6291,6292,810,[8110,8131],[8132,8151],[8152,8163],[8164,8171]],gaps:[4,8,12],lengths:[14,15,16,17,18,19],code:{name:"CVN",size:3}},maestro:{niceType:"Maestro",type:"maestro",patterns:[493698,[5e5,504174],[504176,506698],[506779,508999],[56,59],63,67,6],gaps:[4,8,12],lengths:[12,13,14,15,16,17,18,19],code:{name:"CVC",size:3}},elo:{niceType:"Elo",type:"elo",patterns:[401178,401179,438935,457631,457632,431274,451416,457393,504175,[506699,506778],[509e3,509999],627780,636297,636368,[650031,650033],[650035,650051],[650405,650439],[650485,650538],[650541,650598],[650700,650718],[650720,650727],[650901,650978],[651652,651679],[655e3,655019],[655021,655058]],gaps:[4,8,12],lengths:[16],code:{name:"CVE",size:3}},mir:{niceType:"Mir",type:"mir",patterns:[[2200,2204]],gaps:[4,8,12],lengths:[16,17,18,19],code:{name:"CVP2",size:3}},hiper:{niceType:"Hiper",type:"hiper",patterns:[637095,63737423,63743358,637568,637599,637609,637612],gaps:[4,8,12],lengths:[16],code:{name:"CVC",size:3}},hipercard:{niceType:"Hipercard",type:"hipercard",patterns:[606282],gaps:[4,8,12],lengths:[16],code:{name:"CVC",size:3}}},ml=gl,ti={},bn={};Object.defineProperty(bn,"__esModule",{value:!0});bn.clone=void 0;function vl(e){return e?JSON.parse(JSON.stringify(e)):null}bn.clone=vl;var ri={};Object.defineProperty(ri,"__esModule",{value:!0});ri.matches=void 0;function yl(e,r,n){var a=String(r).length,s=e.substr(0,a),l=parseInt(s,10);return r=parseInt(String(r).substr(0,s.length),10),n=parseInt(String(n).substr(0,s.length),10),l>=r&&l<=n}function bl(e,r){return r=String(r),r.substring(0,e.length)===e.substring(0,r.length)}function _l(e,r){return Array.isArray(r)?yl(e,r[0],r[1]):bl(e,r)}ri.matches=_l;Object.defineProperty(ti,"__esModule",{value:!0});ti.addMatchingCardsToResults=void 0;var wl=bn,xl=ri;function Sl(e,r,n){var a,s;for(a=0;a=s&&(v.matchStrength=s),n.push(v);break}}}ti.addMatchingCardsToResults=Sl;var ni={};Object.defineProperty(ni,"__esModule",{value:!0});ni.isValidInputType=void 0;function El(e){return typeof e=="string"||e instanceof String}ni.isValidInputType=El;var ii={};Object.defineProperty(ii,"__esModule",{value:!0});ii.findBestMatch=void 0;function Ol(e){var r=e.filter(function(n){return n.matchStrength}).length;return r>0&&r===e.length}function Cl(e){return Ol(e)?e.reduce(function(r,n){return!r||Number(r.matchStrength)Ml?pn(!1,!1):Nl.test(e)?pn(!1,!0):pn(!0,!0)}ai.cardholderName=kl;var oi={};function Ll(e){for(var r=0,n=!1,a=e.length-1,s;a>=0;)s=parseInt(e.charAt(a),10),n&&(s*=2,s>9&&(s=s%10+1)),n=!n,r+=s,a--;return r%10===0}var jl=Ll;Object.defineProperty(oi,"__esModule",{value:!0});oi.cardNumber=void 0;var Il=jl,Ga=No;function gr(e,r,n){return{card:e,isPotentiallyValid:r,isValid:n}}function Dl(e,r){r===void 0&&(r={});var n,a,s;if(typeof e!="string"&&typeof e!="number")return gr(null,!1,!1);var l=String(e).replace(/-|\s/g,"");if(!/^\d*$/.test(l))return gr(null,!1,!1);var v=Ga(l);if(v.length===0)return gr(null,!1,!1);if(v.length!==1)return gr(null,!0,!1);var m=v[0];if(r.maxLength&&l.length>r.maxLength)return gr(m,!1,!1);m.type===Ga.types.UNIONPAY&&r.luhnValidateUnionPay!==!0?a=!0:a=Il(l),s=Math.max.apply(null,m.lengths),r.maxLength&&(s=Math.min(r.maxLength,s));for(var L=0;L4)return er(!1,!1);var m=parseInt(e,10),L=Number(String(s).substr(2,2)),q=!1;if(a===2){if(String(s).substr(0,2)===e)return er(!1,!0);n=L===m,q=m>=L&&m<=L+r}else a===4&&(n=s===m,q=m>=s&&m<=s+r);return er(q,q,n)}zr.expirationYear=Fl;var ui={};Object.defineProperty(ui,"__esModule",{value:!0});ui.isArray=void 0;ui.isArray=Array.isArray||function(e){return Object.prototype.toString.call(e)==="[object Array]"};Object.defineProperty(li,"__esModule",{value:!0});li.parseDate=void 0;var Bl=zr,Ul=ui;function Hl(e){var r=Number(e[0]),n;return r===0?2:r>1||r===1&&Number(e[1])>2?1:r===1?(n=e.substr(1),Bl.expirationYear(n).isPotentiallyValid?1:2):e.length===5?1:e.length>5?2:1}function ql(e){var r;if(/^\d{4}-\d{1,2}$/.test(e)?r=e.split("-").reverse():/\//.test(e)?r=e.split(/\s*\/\s*/g):/\s/.test(e)&&(r=e.split(/ +/g)),Ul.isArray(r))return{month:r[0]||"",year:r.slice(1).join()};var n=Hl(e),a=e.substr(0,n);return{month:a,year:e.substr(a.length)}}li.parseDate=ql;var wn={};Object.defineProperty(wn,"__esModule",{value:!0});wn.expirationMonth=void 0;function hn(e,r,n){return{isValid:e,isPotentiallyValid:r,isValidForThisYear:n||!1}}function Vl(e){var r=new Date().getMonth()+1;if(typeof e!="string")return hn(!1,!1);if(e.replace(/\s/g,"")===""||e==="0")return hn(!1,!0);if(!/^\d*$/.test(e))return hn(!1,!1);var n=parseInt(e,10);if(isNaN(Number(e)))return hn(!1,!1);var a=n>0&&n<13;return hn(a,a,a&&n>=r)}wn.expirationMonth=Vl;var Zi=Ht&&Ht.__assign||function(){return Zi=Object.assign||function(e){for(var r,n=1,a=arguments.length;nr?e[n]:r;return r}function Ir(e,r){return{isValid:e,isPotentiallyValid:r}}function Xl(e,r){return r===void 0&&(r=Mo),r=r instanceof Array?r:[r],typeof e!="string"||!/^\d*$/.test(e)?Ir(!1,!1):Gl(r,e.length)?Ir(!0,!0):e.lengthYl(r)?Ir(!1,!1):Ir(!0,!0)}ci.cvv=Xl;var fi={};Object.defineProperty(fi,"__esModule",{value:!0});fi.postalCode=void 0;var Ql=3;function Wi(e,r){return{isValid:e,isPotentiallyValid:r}}function Zl(e,r){r===void 0&&(r={});var n=r.minLength||Ql;return typeof e!="string"?Wi(!1,!1):e.lengthfunction(){return r||(0,e[Lo(e)[0]])((r={exports:{}}).exports,r),r.exports},yu=(e,r,n,a)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of Lo(r))!vu.call(e,s)&&s!==n&&ko(e,s,{get:()=>r[s],enumerable:!(a=gu(r,s))||a.enumerable});return e},rt=(e,r,n)=>(n=e!=null?hu(mu(e)):{},yu(r||!e||!e.__esModule?ko(n,"default",{value:e,enumerable:!0}):n,e)),wt=Yt({"../alpine/packages/alpinejs/dist/module.cjs.js"(e,r){var n=Object.create,a=Object.defineProperty,s=Object.getOwnPropertyDescriptor,l=Object.getOwnPropertyNames,v=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty,L=(t,i)=>function(){return i||(0,t[l(t)[0]])((i={exports:{}}).exports,i),i.exports},q=(t,i)=>{for(var o in i)a(t,o,{get:i[o],enumerable:!0})},ce=(t,i,o,c)=>{if(i&&typeof i=="object"||typeof i=="function")for(let p of l(i))!m.call(t,p)&&p!==o&&a(t,p,{get:()=>i[p],enumerable:!(c=s(i,p))||c.enumerable});return t},se=(t,i,o)=>(o=t!=null?n(v(t)):{},ce(i||!t||!t.__esModule?a(o,"default",{value:t,enumerable:!0}):o,t)),K=t=>ce(a({},"__esModule",{value:!0}),t),Y=L({"node_modules/@vue/shared/dist/shared.cjs.js"(t){Object.defineProperty(t,"__esModule",{value:!0});function i(b,W){const ee=Object.create(null),le=b.split(",");for(let qe=0;qe!!ee[qe.toLowerCase()]:qe=>!!ee[qe]}var o={1:"TEXT",2:"CLASS",4:"STYLE",8:"PROPS",16:"FULL_PROPS",32:"HYDRATE_EVENTS",64:"STABLE_FRAGMENT",128:"KEYED_FRAGMENT",256:"UNKEYED_FRAGMENT",512:"NEED_PATCH",1024:"DYNAMIC_SLOTS",2048:"DEV_ROOT_FRAGMENT",[-1]:"HOISTED",[-2]:"BAIL"},c={1:"STABLE",2:"DYNAMIC",3:"FORWARDED"},p="Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt",d=i(p),g=2;function x(b,W=0,ee=b.length){let le=b.split(/(\r?\n)/);const qe=le.filter((yt,ct)=>ct%2===1);le=le.filter((yt,ct)=>ct%2===0);let tt=0;const vt=[];for(let yt=0;yt=W){for(let ct=yt-g;ct<=yt+g||ee>tt;ct++){if(ct<0||ct>=le.length)continue;const fn=ct+1;vt.push(`${fn}${" ".repeat(Math.max(3-String(fn).length,0))}| ${le[ct]}`);const Lr=le[ct].length,Gn=qe[ct]&&qe[ct].length||0;if(ct===yt){const jr=W-(tt-(Lr+Gn)),Vi=Math.max(1,ee>tt?Lr-jr:ee-W);vt.push(" | "+" ".repeat(jr)+"^".repeat(Vi))}else if(ct>yt){if(ee>tt){const jr=Math.max(Math.min(ee-tt,Lr),1);vt.push(" | "+"^".repeat(jr))}tt+=Lr+Gn}}break}return vt.join(` -`)}var k="itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly",Z=i(k),Me=i(k+",async,autofocus,autoplay,controls,default,defer,disabled,hidden,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected"),Qe=/[>/="'\u0009\u000a\u000c\u0020]/,$e={};function Ke(b){if($e.hasOwnProperty(b))return $e[b];const W=Qe.test(b);return W&&console.error(`unsafe attribute name: ${b}`),$e[b]=!W}var At={acceptCharset:"accept-charset",className:"class",htmlFor:"for",httpEquiv:"http-equiv"},Ft=i("animation-iteration-count,border-image-outset,border-image-slice,border-image-width,box-flex,box-flex-group,box-ordinal-group,column-count,columns,flex,flex-grow,flex-positive,flex-shrink,flex-negative,flex-order,grid-row,grid-row-end,grid-row-span,grid-row-start,grid-column,grid-column-end,grid-column-span,grid-column-start,font-weight,line-clamp,line-height,opacity,order,orphans,tab-size,widows,z-index,zoom,fill-opacity,flood-opacity,stop-opacity,stroke-dasharray,stroke-dashoffset,stroke-miterlimit,stroke-opacity,stroke-width"),Se=i("accept,accept-charset,accesskey,action,align,allow,alt,async,autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,border,buffered,capture,challenge,charset,checked,cite,class,code,codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,formaction,formenctype,formmethod,formnovalidate,formtarget,headers,height,hidden,high,href,hreflang,http-equiv,icon,id,importance,integrity,ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,target,title,translate,type,usemap,value,width,wrap");function Ue(b){if(Nt(b)){const W={};for(let ee=0;ee{if(ee){const le=ee.split(He);le.length>1&&(W[le[0].trim()]=le[1].trim())}}),W}function Rt(b){let W="";if(!b)return W;for(const ee in b){const le=b[ee],qe=ee.startsWith("--")?ee:Kn(ee);(fr(le)||typeof le=="number"&&Ft(qe))&&(W+=`${qe}:${le};`)}return W}function Bt(b){let W="";if(fr(b))W=b;else if(Nt(b))for(let ee=0;ee]/;function Li(b){const W=""+b,ee=ki.exec(W);if(!ee)return W;let le="",qe,tt,vt=0;for(tt=ee.index;tt||--!>|Or(ee,W))}var In=b=>b==null?"":Ut(b)?JSON.stringify(b,Di,2):String(b),Di=(b,W)=>cr(W)?{[`Map(${W.size})`]:[...W.entries()].reduce((ee,[le,qe])=>(ee[`${le} =>`]=qe,ee),{})}:Mt(W)?{[`Set(${W.size})`]:[...W.values()]}:Ut(W)&&!Nt(W)&&!Hn(W)?String(W):W,$i=["bigInt","optionalChaining","nullishCoalescingOperator"],an=Object.freeze({}),on=Object.freeze([]),sn=()=>{},Cr=()=>!1,Ar=/^on[^a-z]/,Tr=b=>Ar.test(b),Pr=b=>b.startsWith("onUpdate:"),Dn=Object.assign,$n=(b,W)=>{const ee=b.indexOf(W);ee>-1&&b.splice(ee,1)},Fn=Object.prototype.hasOwnProperty,Bn=(b,W)=>Fn.call(b,W),Nt=Array.isArray,cr=b=>dr(b)==="[object Map]",Mt=b=>dr(b)==="[object Set]",ln=b=>b instanceof Date,un=b=>typeof b=="function",fr=b=>typeof b=="string",Fi=b=>typeof b=="symbol",Ut=b=>b!==null&&typeof b=="object",Rr=b=>Ut(b)&&un(b.then)&&un(b.catch),Un=Object.prototype.toString,dr=b=>Un.call(b),Bi=b=>dr(b).slice(8,-1),Hn=b=>dr(b)==="[object Object]",qn=b=>fr(b)&&b!=="NaN"&&b[0]!=="-"&&""+parseInt(b,10)===b,Vn=i(",key,ref,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),pr=b=>{const W=Object.create(null);return ee=>W[ee]||(W[ee]=b(ee))},zn=/-(\w)/g,Wn=pr(b=>b.replace(zn,(W,ee)=>ee?ee.toUpperCase():"")),Ui=/\B([A-Z])/g,Kn=pr(b=>b.replace(Ui,"-$1").toLowerCase()),hr=pr(b=>b.charAt(0).toUpperCase()+b.slice(1)),Hi=pr(b=>b?`on${hr(b)}`:""),cn=(b,W)=>b!==W&&(b===b||W===W),qi=(b,W)=>{for(let ee=0;ee{Object.defineProperty(b,W,{configurable:!0,enumerable:!1,value:ee})},Mr=b=>{const W=parseFloat(b);return isNaN(W)?b:W},kr,Jn=()=>kr||(kr=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});t.EMPTY_ARR=on,t.EMPTY_OBJ=an,t.NO=Cr,t.NOOP=sn,t.PatchFlagNames=o,t.babelParserDefaultPlugins=$i,t.camelize=Wn,t.capitalize=hr,t.def=Nr,t.escapeHtml=Li,t.escapeHtmlComment=ji,t.extend=Dn,t.generateCodeFrame=x,t.getGlobalThis=Jn,t.hasChanged=cn,t.hasOwn=Bn,t.hyphenate=Kn,t.invokeArrayFns=qi,t.isArray=Nt,t.isBooleanAttr=Me,t.isDate=ln,t.isFunction=un,t.isGloballyWhitelisted=d,t.isHTMLTag=Sr,t.isIntegerKey=qn,t.isKnownAttr=Se,t.isMap=cr,t.isModelListener=Pr,t.isNoUnitNumericStyleProp=Ft,t.isObject=Ut,t.isOn=Tr,t.isPlainObject=Hn,t.isPromise=Rr,t.isReservedProp=Vn,t.isSSRSafeAttrName=Ke,t.isSVGTag=Mi,t.isSet=Mt,t.isSpecialBooleanAttr=Z,t.isString=fr,t.isSymbol=Fi,t.isVoidTag=Er,t.looseEqual=Or,t.looseIndexOf=jn,t.makeMap=i,t.normalizeClass=Bt,t.normalizeStyle=Ue,t.objectToString=Un,t.parseStringStyle=mt,t.propsToAttrMap=At,t.remove=$n,t.slotFlagsText=c,t.stringifyStyle=Rt,t.toDisplayString=In,t.toHandlerKey=Hi,t.toNumber=Mr,t.toRawType=Bi,t.toTypeString=dr}}),E=L({"node_modules/@vue/shared/index.js"(t,i){i.exports=Y()}}),y=L({"node_modules/@vue/reactivity/dist/reactivity.cjs.js"(t){Object.defineProperty(t,"__esModule",{value:!0});var i=E(),o=new WeakMap,c=[],p,d=Symbol("iterate"),g=Symbol("Map key iterate");function x(u){return u&&u._isEffect===!0}function k(u,T=i.EMPTY_OBJ){x(u)&&(u=u.raw);const N=Qe(u,T);return T.lazy||N(),N}function Z(u){u.active&&($e(u),u.options.onStop&&u.options.onStop(),u.active=!1)}var Me=0;function Qe(u,T){const N=function(){if(!N.active)return u();if(!c.includes(N)){$e(N);try{return Se(),c.push(N),p=N,u()}finally{c.pop(),Ue(),p=c[c.length-1]}}};return N.id=Me++,N.allowRecurse=!!T.allowRecurse,N._isEffect=!0,N.active=!0,N.raw=u,N.deps=[],N.options=T,N}function $e(u){const{deps:T}=u;if(T.length){for(let N=0;N{ht&&ht.forEach(kt=>{(kt!==p||kt.allowRecurse)&&it.add(kt)})};if(T==="clear")je.forEach(bt);else if(N==="length"&&i.isArray(u))je.forEach((ht,kt)=>{(kt==="length"||kt>=ie)&&bt(ht)});else switch(N!==void 0&&bt(je.get(N)),T){case"add":i.isArray(u)?i.isIntegerKey(N)&&bt(je.get("length")):(bt(je.get(d)),i.isMap(u)&&bt(je.get(g)));break;case"delete":i.isArray(u)||(bt(je.get(d)),i.isMap(u)&&bt(je.get(g)));break;case"set":i.isMap(u)&&bt(je.get(d));break}const dn=ht=>{ht.options.onTrigger&&ht.options.onTrigger({effect:ht,target:u,key:N,type:T,newValue:ie,oldValue:J,oldTarget:me}),ht.options.scheduler?ht.options.scheduler(ht):ht()};it.forEach(dn)}var mt=i.makeMap("__proto__,__v_isRef,__isVue"),Rt=new Set(Object.getOwnPropertyNames(Symbol).map(u=>Symbol[u]).filter(i.isSymbol)),Bt=Er(),xr=Er(!1,!0),rn=Er(!0),nn=Er(!0,!0),Sr=Mi();function Mi(){const u={};return["includes","indexOf","lastIndexOf"].forEach(T=>{u[T]=function(...N){const ie=b(this);for(let me=0,je=this.length;me{u[T]=function(...N){Ft();const ie=b(this)[T].apply(this,N);return Ue(),ie}}),u}function Er(u=!1,T=!1){return function(ie,J,me){if(J==="__v_isReactive")return!u;if(J==="__v_isReadonly")return u;if(J==="__v_raw"&&me===(u?T?Wn:zn:T?pr:Vn).get(ie))return ie;const je=i.isArray(ie);if(!u&&je&&i.hasOwn(Sr,J))return Reflect.get(Sr,J,me);const it=Reflect.get(ie,J,me);return(i.isSymbol(J)?Rt.has(J):mt(J))||(u||Le(ie,"get",J),T)?it:le(it)?!je||!i.isIntegerKey(J)?it.value:it:i.isObject(it)?u?cn(it):hr(it):it}}var ki=Ln(),Li=Ln(!0);function Ln(u=!1){return function(N,ie,J,me){let je=N[ie];if(!u&&(J=b(J),je=b(je),!i.isArray(N)&&le(je)&&!le(J)))return je.value=J,!0;const it=i.isArray(N)&&i.isIntegerKey(ie)?Number(ie)i.isObject(u)?hr(u):u,on=u=>i.isObject(u)?cn(u):u,sn=u=>u,Cr=u=>Reflect.getPrototypeOf(u);function Ar(u,T,N=!1,ie=!1){u=u.__v_raw;const J=b(u),me=b(T);T!==me&&!N&&Le(J,"get",T),!N&&Le(J,"get",me);const{has:je}=Cr(J),it=ie?sn:N?on:an;if(je.call(J,T))return it(u.get(T));if(je.call(J,me))return it(u.get(me));u!==J&&u.get(T)}function Tr(u,T=!1){const N=this.__v_raw,ie=b(N),J=b(u);return u!==J&&!T&&Le(ie,"has",u),!T&&Le(ie,"has",J),u===J?N.has(u):N.has(u)||N.has(J)}function Pr(u,T=!1){return u=u.__v_raw,!T&&Le(b(u),"iterate",d),Reflect.get(u,"size",u)}function Dn(u){u=b(u);const T=b(this);return Cr(T).has.call(T,u)||(T.add(u),He(T,"add",u,u)),this}function $n(u,T){T=b(T);const N=b(this),{has:ie,get:J}=Cr(N);let me=ie.call(N,u);me?qn(N,ie,u):(u=b(u),me=ie.call(N,u));const je=J.call(N,u);return N.set(u,T),me?i.hasChanged(T,je)&&He(N,"set",u,T,je):He(N,"add",u,T),this}function Fn(u){const T=b(this),{has:N,get:ie}=Cr(T);let J=N.call(T,u);J?qn(T,N,u):(u=b(u),J=N.call(T,u));const me=ie?ie.call(T,u):void 0,je=T.delete(u);return J&&He(T,"delete",u,void 0,me),je}function Bn(){const u=b(this),T=u.size!==0,N=i.isMap(u)?new Map(u):new Set(u),ie=u.clear();return T&&He(u,"clear",void 0,void 0,N),ie}function Nt(u,T){return function(ie,J){const me=this,je=me.__v_raw,it=b(je),bt=T?sn:u?on:an;return!u&&Le(it,"iterate",d),je.forEach((dn,ht)=>ie.call(J,bt(dn),bt(ht),me))}}function cr(u,T,N){return function(...ie){const J=this.__v_raw,me=b(J),je=i.isMap(me),it=u==="entries"||u===Symbol.iterator&&je,bt=u==="keys"&&je,dn=J[u](...ie),ht=N?sn:T?on:an;return!T&&Le(me,"iterate",bt?g:d),{next(){const{value:kt,done:zi}=dn.next();return zi?{value:kt,done:zi}:{value:it?[ht(kt[0]),ht(kt[1])]:ht(kt),done:zi}},[Symbol.iterator](){return this}}}}function Mt(u){return function(...T){{const N=T[0]?`on key "${T[0]}" `:"";console.warn(`${i.capitalize(u)} operation ${N}failed: target is readonly.`,b(this))}return u==="delete"?!1:this}}function ln(){const u={get(me){return Ar(this,me)},get size(){return Pr(this)},has:Tr,add:Dn,set:$n,delete:Fn,clear:Bn,forEach:Nt(!1,!1)},T={get(me){return Ar(this,me,!1,!0)},get size(){return Pr(this)},has:Tr,add:Dn,set:$n,delete:Fn,clear:Bn,forEach:Nt(!1,!0)},N={get(me){return Ar(this,me,!0)},get size(){return Pr(this,!0)},has(me){return Tr.call(this,me,!0)},add:Mt("add"),set:Mt("set"),delete:Mt("delete"),clear:Mt("clear"),forEach:Nt(!0,!1)},ie={get(me){return Ar(this,me,!0,!0)},get size(){return Pr(this,!0)},has(me){return Tr.call(this,me,!0)},add:Mt("add"),set:Mt("set"),delete:Mt("delete"),clear:Mt("clear"),forEach:Nt(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(me=>{u[me]=cr(me,!1,!1),N[me]=cr(me,!0,!1),T[me]=cr(me,!1,!0),ie[me]=cr(me,!0,!0)}),[u,N,T,ie]}var[un,fr,Fi,Ut]=ln();function Rr(u,T){const N=T?u?Ut:Fi:u?fr:un;return(ie,J,me)=>J==="__v_isReactive"?!u:J==="__v_isReadonly"?u:J==="__v_raw"?ie:Reflect.get(i.hasOwn(N,J)&&J in ie?N:ie,J,me)}var Un={get:Rr(!1,!1)},dr={get:Rr(!1,!0)},Bi={get:Rr(!0,!1)},Hn={get:Rr(!0,!0)};function qn(u,T,N){const ie=b(N);if(ie!==N&&T.call(u,ie)){const J=i.toRawType(u);console.warn(`Reactive ${J} contains both the raw and reactive versions of the same object${J==="Map"?" as keys":""}, which can lead to inconsistencies. Avoid differentiating between the raw and reactive versions of an object and only use the reactive version if possible.`)}}var Vn=new WeakMap,pr=new WeakMap,zn=new WeakMap,Wn=new WeakMap;function Ui(u){switch(u){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Kn(u){return u.__v_skip||!Object.isExtensible(u)?0:Ui(i.toRawType(u))}function hr(u){return u&&u.__v_isReadonly?u:Nr(u,!1,jn,Un,Vn)}function Hi(u){return Nr(u,!1,Di,dr,pr)}function cn(u){return Nr(u,!0,In,Bi,zn)}function qi(u){return Nr(u,!0,$i,Hn,Wn)}function Nr(u,T,N,ie,J){if(!i.isObject(u))return console.warn(`value cannot be made reactive: ${String(u)}`),u;if(u.__v_raw&&!(T&&u.__v_isReactive))return u;const me=J.get(u);if(me)return me;const je=Kn(u);if(je===0)return u;const it=new Proxy(u,je===2?ie:N);return J.set(u,it),it}function Mr(u){return kr(u)?Mr(u.__v_raw):!!(u&&u.__v_isReactive)}function kr(u){return!!(u&&u.__v_isReadonly)}function Jn(u){return Mr(u)||kr(u)}function b(u){return u&&b(u.__v_raw)||u}function W(u){return i.def(u,"__v_skip",!0),u}var ee=u=>i.isObject(u)?hr(u):u;function le(u){return!!(u&&u.__v_isRef===!0)}function qe(u){return yt(u)}function tt(u){return yt(u,!0)}var vt=class{constructor(u,T=!1){this._shallow=T,this.__v_isRef=!0,this._rawValue=T?u:b(u),this._value=T?u:ee(u)}get value(){return Le(b(this),"get","value"),this._value}set value(u){u=this._shallow?u:b(u),i.hasChanged(u,this._rawValue)&&(this._rawValue=u,this._value=this._shallow?u:ee(u),He(b(this),"set","value",u))}};function yt(u,T=!1){return le(u)?u:new vt(u,T)}function ct(u){He(b(u),"set","value",u.value)}function fn(u){return le(u)?u.value:u}var Lr={get:(u,T,N)=>fn(Reflect.get(u,T,N)),set:(u,T,N,ie)=>{const J=u[T];return le(J)&&!le(N)?(J.value=N,!0):Reflect.set(u,T,N,ie)}};function Gn(u){return Mr(u)?u:new Proxy(u,Lr)}var jr=class{constructor(u){this.__v_isRef=!0;const{get:T,set:N}=u(()=>Le(this,"get","value"),()=>He(this,"set","value"));this._get=T,this._set=N}get value(){return this._get()}set value(u){this._set(u)}};function Vi(u){return new jr(u)}function ul(u){Jn(u)||console.warn("toRefs() expects a reactive object but received a plain one.");const T=i.isArray(u)?new Array(u.length):{};for(const N in u)T[N]=Ja(u,N);return T}var cl=class{constructor(u,T){this._object=u,this._key=T,this.__v_isRef=!0}get value(){return this._object[this._key]}set value(u){this._object[this._key]=u}};function Ja(u,T){return le(u[T])?u[T]:new cl(u,T)}var fl=class{constructor(u,T,N){this._setter=T,this._dirty=!0,this.__v_isRef=!0,this.effect=k(u,{lazy:!0,scheduler:()=>{this._dirty||(this._dirty=!0,He(b(this),"set","value"))}}),this.__v_isReadonly=N}get value(){const u=b(this);return u._dirty&&(u._value=this.effect(),u._dirty=!1),Le(u,"get","value"),u._value}set value(u){this._setter(u)}};function dl(u){let T,N;return i.isFunction(u)?(T=u,N=()=>{console.warn("Write operation failed: computed value is readonly")}):(T=u.get,N=u.set),new fl(T,N,i.isFunction(u)||!u.set)}t.ITERATE_KEY=d,t.computed=dl,t.customRef=Vi,t.effect=k,t.enableTracking=Se,t.isProxy=Jn,t.isReactive=Mr,t.isReadonly=kr,t.isRef=le,t.markRaw=W,t.pauseTracking=Ft,t.proxyRefs=Gn,t.reactive=hr,t.readonly=cn,t.ref=qe,t.resetTracking=Ue,t.shallowReactive=Hi,t.shallowReadonly=qi,t.shallowRef=tt,t.stop=Z,t.toRaw=b,t.toRef=Ja,t.toRefs=ul,t.track=Le,t.trigger=He,t.triggerRef=ct,t.unref=fn}}),_=L({"node_modules/@vue/reactivity/index.js"(t,i){i.exports=y()}}),O={};q(O,{Alpine:()=>Ka,default:()=>ll}),r.exports=K(O);var R=!1,I=!1,U=[],Re=-1;function D(t){C(t)}function C(t){U.includes(t)||U.push(t),te()}function M(t){let i=U.indexOf(t);i!==-1&&i>Re&&U.splice(i,1)}function te(){!I&&!R&&(R=!0,queueMicrotask(be))}function be(){R=!1,I=!0;for(let t=0;tt.effect(i,{scheduler:o=>{Ge?D(o):o()}}),Je=t.raw}function dt(t){Q=t}function xt(t){let i=()=>{};return[c=>{let p=Q(c);return t._x_effects||(t._x_effects=new Set,t._x_runEffects=()=>{t._x_effects.forEach(d=>d())}),t._x_effects.add(p),i=()=>{p!==void 0&&(t._x_effects.delete(p),Pe(p))},p},()=>{i()}]}function Et(t,i){let o=!0,c,p=Q(()=>{let d=t();JSON.stringify(d),o?c=d:queueMicrotask(()=>{i(d,c),c=d}),o=!1});return()=>Pe(p)}function we(t,i,o={}){t.dispatchEvent(new CustomEvent(i,{detail:o,bubbles:!0,composed:!0,cancelable:!0}))}function ue(t,i){if(typeof ShadowRoot=="function"&&t instanceof ShadowRoot){Array.from(t.children).forEach(p=>ue(p,i));return}let o=!1;if(i(t,()=>o=!0),o)return;let c=t.firstElementChild;for(;c;)ue(c,i),c=c.nextElementSibling}function fe(t,...i){console.warn(`Alpine Warning: ${t}`,...i)}var Ee=!1;function ve(){Ee&&fe("Alpine has already been initialized on this page. Calling Alpine.start() more than once can cause problems."),Ee=!0,document.body||fe("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's `