1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 05:02:36 +01:00

Merge branch 'v5-develop' into l9

This commit is contained in:
David Bomba 2022-07-21 14:22:45 +10:00
commit 93c782fcc5
17 changed files with 5139 additions and 109 deletions

View File

@ -99,6 +99,7 @@ class InvoiceItemExport extends BaseExport
public function run()
{
MultiDB::setDb($this->company->db);
App::forgetInstance('translator');
App::setLocale($this->company->locale());
@ -108,25 +109,27 @@ class InvoiceItemExport extends BaseExport
//load the CSV document from a string
$this->csv = Writer::createFromString();
if (count($this->input['report_keys']) == 0) {
if(count($this->input['report_keys']) == 0)
$this->input['report_keys'] = array_values($this->entity_keys);
}
//insert the header
$this->csv->insertOne($this->buildHeader());
$query = Invoice::query()
->with('client')->where('company_id', $this->company->id)
->where('is_deleted', 0);
->where('is_deleted',0);
$query = $this->addDateRange($query);
$query->cursor()
->each(function ($invoice) {
$this->iterateItems($invoice);
});
->each(function ($invoice){
$this->iterateItems($invoice);
});
return $this->csv->toString();
return $this->csv->toString();
}
private function iterateItems(Invoice $invoice)
@ -135,68 +138,81 @@ class InvoiceItemExport extends BaseExport
$transformed_items = [];
foreach ($invoice->line_items as $item) {
foreach($invoice->line_items as $item)
{
$item_array = [];
foreach (array_values($this->input['report_keys']) as $key) {
if (str_contains($key, 'item.')) {
$key = str_replace('item.', '', $key);
$item_array[$key] = $item->{$key};
foreach(array_values($this->input['report_keys']) as $key){
if(str_contains($key, "item.")){
$key = str_replace("item.", "", $key);
if(property_exists($item, $key))
$item_array[$key] = $item->{$key};
else
$item_array[$key] = '';
}
}
$entity = [];
foreach (array_values($this->input['report_keys']) as $key) {
foreach(array_values($this->input['report_keys']) as $key)
{
$keyval = array_search($key, $this->entity_keys);
if (array_key_exists($key, $transformed_items)) {
if(array_key_exists($key, $transformed_items))
$entity[$keyval] = $transformed_items[$key];
} else {
$entity[$keyval] = '';
}
else
$entity[$keyval] = "";
}
$transformed_items = array_merge($transformed_invoice, $item_array);
$entity = $this->decorateAdvancedFields($invoice, $transformed_items);
$this->csv->insertOne($entity);
$this->csv->insertOne($entity);
}
}
private function buildRow(Invoice $invoice) :array
{
$transformed_invoice = $this->invoice_transformer->transform($invoice);
$entity = [];
foreach (array_values($this->input['report_keys']) as $key) {
foreach(array_values($this->input['report_keys']) as $key){
$keyval = array_search($key, $this->entity_keys);
if (array_key_exists($key, $transformed_invoice)) {
if(array_key_exists($key, $transformed_invoice))
$entity[$keyval] = $transformed_invoice[$key];
} else {
$entity[$keyval] = '';
}
else
$entity[$keyval] = "";
}
return $this->decorateAdvancedFields($invoice, $entity);
}
private function decorateAdvancedFields(Invoice $invoice, array $entity) :array
{
if (in_array('currency_id', $this->input['report_keys'])) {
if(in_array('currency_id', $this->input['report_keys']))
$entity['currency'] = $invoice->client->currency() ? $invoice->client->currency()->code : $invoice->company->currency()->code;
}
if (in_array('client_id', $this->input['report_keys'])) {
if(in_array('client_id', $this->input['report_keys']))
$entity['client'] = $invoice->client->present()->name();
}
if (in_array('status_id', $this->input['report_keys'])) {
if(in_array('status_id', $this->input['report_keys']))
$entity['status'] = $invoice->stringStatus($invoice->status_id);
}
return $entity;
}
}

View File

@ -182,6 +182,7 @@ class MigrationController extends BaseController
$company->vendors()->forceDelete();
$company->expenses()->forceDelete();
$company->purchase_orders()->forceDelete();
$company->all_activities()->forceDelete();
$settings = $company->settings;

View File

@ -469,6 +469,7 @@ class CompanyImport implements ShouldQueue
private function purgeCompanyData()
{
$this->company->clients()->forceDelete();
$this->company->all_activities()->forceDelete();
$this->company->products()->forceDelete();
$this->company->projects()->forceDelete();
$this->company->tasks()->forceDelete();

View File

@ -22,7 +22,7 @@ class CompanyGateway extends BaseModel
{
use SoftDeletes;
use Filterable;
public const GATEWAY_CREDIT = 10000000;
protected $casts = [
@ -54,12 +54,13 @@ class CompanyGateway extends BaseModel
];
public static $credit_cards = [
1 => ['card' => 'images/credit_cards/Test-Visa-Icon.png', 'text' => 'Visa'],
2 => ['card' => 'images/credit_cards/Test-MasterCard-Icon.png', 'text' => 'Master Card'],
4 => ['card' => 'images/credit_cards/Test-AmericanExpress-Icon.png', 'text' => 'American Express'],
8 => ['card' => 'images/credit_cards/Test-Diners-Icon.png', 'text' => 'Diners'],
16 => ['card' => 'images/credit_cards/Test-Discover-Icon.png', 'text' => 'Discover'],
];
1 => ['card' => 'images/credit_cards/Test-Visa-Icon.png', 'text' => 'Visa'],
2 => ['card' => 'images/credit_cards/Test-MasterCard-Icon.png', 'text' => 'Master Card'],
4 => ['card' => 'images/credit_cards/Test-AmericanExpress-Icon.png', 'text' => 'American Express'],
8 => ['card' => 'images/credit_cards/Test-Diners-Icon.png', 'text' => 'Diners'],
16 => ['card' => 'images/credit_cards/Test-Discover-Icon.png', 'text' => 'Discover'],
];
// const TYPE_PAYPAL = 300;
// const TYPE_STRIPE = 301;
@ -98,6 +99,7 @@ class CompanyGateway extends BaseModel
public function system_logs()
{
return $this->company
->system_log_relation
->where('type_id', $this->gateway_consts[$this->gateway->key])
@ -129,11 +131,11 @@ class CompanyGateway extends BaseModel
{
$class = static::driver_class();
if (! $class) {
if(!$class)
return false;
}
return new $class($this, $client);
}
private function driver_class()
@ -141,10 +143,9 @@ class CompanyGateway extends BaseModel
$class = 'App\\PaymentDrivers\\'.$this->gateway->provider.'PaymentDriver';
$class = str_replace('_', '', $class);
if (class_exists($class)) {
if (class_exists($class))
return $class;
}
return false;
// throw new \Exception("Payment Driver does not exist");
@ -275,7 +276,7 @@ class CompanyGateway extends BaseModel
public function getFeesAndLimits($gateway_type_id)
{
if (is_null($this->fees_and_limits) || empty($this->fees_and_limits) || ! property_exists($this->fees_and_limits, $gateway_type_id)) {
if (is_null($this->fees_and_limits) || empty($this->fees_and_limits) || !property_exists($this->fees_and_limits, $gateway_type_id)) {
return false;
}
@ -300,27 +301,28 @@ class CompanyGateway extends BaseModel
$fee = $this->calcGatewayFee($amount, $gateway_type_id);
// if ($fee > 0) {
// $fee = Number::formatMoney(round($fee, 2), $client);
// $label = ' - '.$fee.' '.ctrans('texts.fee');
// }
if($fee > 0) {
if ($fee > 0) {
$fees_and_limits = $this->fees_and_limits->{$gateway_type_id};
if (strlen($fees_and_limits->fee_percent) >= 1) {
$label .= $fees_and_limits->fee_percent.'%';
}
if(strlen($fees_and_limits->fee_percent) >=1)
$label .= $fees_and_limits->fee_percent . '%';
if (strlen($fees_and_limits->fee_amount) >= 1) {
if (strlen($label) > 1) {
$label .= ' + '.Number::formatMoney($fees_and_limits->fee_amount, $client);
} else {
if(strlen($fees_and_limits->fee_amount) >=1){
if(strlen($label) > 1) {
$label .= ' + ' . Number::formatMoney($fees_and_limits->fee_amount, $client);
}else {
$label .= Number::formatMoney($fees_and_limits->fee_amount, $client);
}
}
}
return $label;
}
@ -334,38 +336,45 @@ class CompanyGateway extends BaseModel
$fee = 0;
if ($fees_and_limits->adjust_fee_percent) {
$adjusted_fee = 0;
if ($fees_and_limits->fee_amount) {
$adjusted_fee += $fees_and_limits->fee_amount + $amount;
} else {
$adjusted_fee = $amount;
}
if($fees_and_limits->adjust_fee_percent)
{
$adjusted_fee = 0;
if ($fees_and_limits->fee_percent) {
$divisor = 1 - ($fees_and_limits->fee_percent / 100);
$gross_amount = round($adjusted_fee / $divisor, 2);
$fee = $gross_amount - $amount;
}
} else {
if ($fees_and_limits->fee_amount) {
$fee += $fees_and_limits->fee_amount;
}
if ($fees_and_limits->fee_percent) {
if ($fees_and_limits->fee_percent == 100) { //unusual edge case if the user wishes to charge a fee of 100% 09/01/2022
$fee += $amount;
} else {
$fee += round(($amount * $fees_and_limits->fee_percent / 100), 2);
if ($fees_and_limits->fee_amount) {
$adjusted_fee += $fees_and_limits->fee_amount + $amount;
}
//elseif ($fees_and_limits->adjust_fee_percent) {
else
$adjusted_fee = $amount;
if ($fees_and_limits->fee_percent) {
$divisor = 1 - ($fees_and_limits->fee_percent/100);
$gross_amount = round($adjusted_fee/$divisor,2);
$fee = $gross_amount - $amount;
}
}
else
{
if ($fees_and_limits->fee_amount) {
$fee += $fees_and_limits->fee_amount;
}
if ($fees_and_limits->fee_percent) {
if($fees_and_limits->fee_percent == 100){ //unusual edge case if the user wishes to charge a fee of 100% 09/01/2022
$fee += $amount;
}
else
$fee += round(($amount * $fees_and_limits->fee_percent / 100), 2);
//elseif ($fees_and_limits->adjust_fee_percent) {
// $fee += round(($amount / (1 - $fees_and_limits->fee_percent / 100) - $amount), 2);
//} else {
//}
}
}
}
/* Cap fee if we have to here. */
if ($fees_and_limits->fee_cap > 0 && ($fee > $fees_and_limits->fee_cap)) {
@ -405,4 +414,6 @@ class CompanyGateway extends BaseModel
return $this
->where('id', $this->decodePrimaryKey($value))->firstOrFail();
}
}

View File

@ -19,8 +19,9 @@ use App\Models\TaskStatus;
*/
class TaskStatusRepository extends BaseRepository
{
public function delete($task_status)
{
public function delete($task_status)
{
$ts = TaskStatus::where('company_id', $task_status->company_id)
->first();
@ -30,24 +31,30 @@ class TaskStatusRepository extends BaseRepository
->where('company_id', $task_status->company_id)
->update(['status_id' => $new_status]);
parent::delete($task_status);
return $task_status;
}
}
public function archive($task_status)
{
$task_status = TaskStatus::where('company_id', $task_status->company_id)
public function archive($task_status)
{
$task_status = TaskStatus::where('id', $task_status->id)
->where('company_id', $task_status->company_id)
->first();
$new_status = $task_status ? $task_status->id : null;
Task::where('status_id', $task_status->id)
->where('company_id', $task_status->company_id)
->update(['status_id' => $new_status]);
parent::archive($task_status);
return $task_status;
}
}
}

View File

@ -499,20 +499,6 @@ class Design extends BaseDesign
$tbody = [];
// foreach ($this->payments as $payment) {
// foreach ($payment->invoices as $invoice) {
// $element = ['element' => 'tr', 'elements' => []];
// $element['elements'][] = ['element' => 'td', 'content' => $invoice->number];
// $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($payment->date, $this->client->date_format(), $this->client->locale()) ?: ' '];
// $element['elements'][] = ['element' => 'td', 'content' => $payment->type ? $payment->type->name : ctrans('texts.manual_entry')];
// $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($payment->amount, $this->client) ?: ' '];
// $tbody[] = $element;
// }
// }
//24-03-2022 show payments per invoice
foreach ($this->invoices as $invoice) {
foreach ($invoice->payments as $payment) {
@ -816,7 +802,7 @@ class Design extends BaseDesign
foreach ($taxes as $i => $tax) {
$elements[1]['elements'][] = ['element' => 'div', 'elements' => [
['element' => 'span', 'content', 'content' => $tax['name'], 'properties' => ['data-ref' => 'totals-table-total_tax_' . $i . '-label']],
['element' => 'span', 'content', 'content' => Number::formatMoney($tax['total'], $this->client_or_vendor_entity), 'properties' => ['data-ref' => 'totals-table-total_tax_' . $i]],
['element' => 'span', 'content', 'content' => Number::formatMoney($tax['total'], $this->entity instanceof \App\Models\PurchaseOrder ? $this->company : $this->client_or_vendor_entity), 'properties' => ['data-ref' => 'totals-table-total_tax_' . $i]],
]];
}
} elseif ($variable == '$line_taxes') {
@ -829,13 +815,13 @@ class Design extends BaseDesign
foreach ($taxes as $i => $tax) {
$elements[1]['elements'][] = ['element' => 'div', 'elements' => [
['element' => 'span', 'content', 'content' => $tax['name'], 'properties' => ['data-ref' => 'totals-table-line_tax_' . $i . '-label']],
['element' => 'span', 'content', 'content' => Number::formatMoney($tax['total'], $this->client_or_vendor_entity), 'properties' => ['data-ref' => 'totals-table-line_tax_' . $i]],
['element' => 'span', 'content', 'content' => Number::formatMoney($tax['total'], $this->entity instanceof \App\Models\PurchaseOrder ? $this->company : $this->client_or_vendor_entity), 'properties' => ['data-ref' => 'totals-table-line_tax_' . $i]],
]];
}
} elseif (Str::startsWith($variable, '$custom_surcharge')) {
$_variable = ltrim($variable, '$'); // $custom_surcharge1 -> custom_surcharge1
$visible = (int)$this->entity->{$_variable} > 0 || (int)$this->entity->{$_variable} < 0 || !$this->entity->{$_variable};
$visible = intval($this->entity->{$_variable}) != 0;
$elements[1]['elements'][] = ['element' => 'div', 'elements' => [
['element' => 'span', 'content' => $variable . '_label', 'properties' => ['hidden' => !$visible, 'data-ref' => 'totals_table-' . substr($variable, 1) . '-label']],

View File

@ -109,6 +109,7 @@ class HtmlEngine
$t->replace(Ninja::transformTranslations($this->settings));
$data = [];
//$data['<html>'] = ['value' => '<html dir="rtl">', 'label' => ''];
$data['$global_margin'] = ['value' => '6.35mm', 'label' => ''];
$data['$tax'] = ['value' => '', 'label' => ctrans('texts.tax')];
$data['$app_url'] = ['value' => $this->generateAppUrl(), 'label' => ''];
@ -541,8 +542,8 @@ class HtmlEngine
$data['$payment_url'] = &$data['$payment_link'];
$data['$portalButton'] = &$data['$paymentLink'];
$data['$dir'] = ['value' => optional($this->client->language())->locale === 'ar' ? 'rtl' : 'ltr', 'label' => ''];
$data['$dir_text_align'] = ['value' => optional($this->client->language())->locale === 'ar' ? 'right' : 'left', 'label' => ''];
$data['$dir'] = ['value' => in_array(optional($this->client->language())->locale, ['ar', 'he']) ? 'rtl' : 'ltr', 'label' => ''];
$data['$dir_text_align'] = ['value' => in_array(optional($this->client->language())->locale, ['ar', 'he']) ? 'right' : 'left', 'label' => ''];
$data['$payment.date'] = ['value' => '&nbsp;', 'label' => ctrans('texts.payment_date')];
$data['$method'] = ['value' => '&nbsp;', 'label' => ctrans('texts.method')];

View File

@ -13,6 +13,7 @@ namespace App\Utils;
use App\Models\Company;
use App\Models\Currency;
use App\Models\Vendor;
/**
* Class Number.
@ -119,6 +120,7 @@ class Number
*/
public static function formatMoney($value, $entity) :string
{
$currency = $entity->currency();
$thousand = $currency->thousand_separator;

View File

@ -391,8 +391,9 @@ class VendorHtmlEngine
$data['$autoBill'] = ['value' => ctrans('texts.auto_bill_notification_placeholder'), 'label' => ''];
$data['$auto_bill'] = &$data['$autoBill'];
$data['$dir'] = ['value' => optional($this->company->language())->locale === 'ar' ? 'rtl' : 'ltr', 'label' => ''];
$data['$dir_text_align'] = ['value' => optional($this->company->language())->locale === 'ar' ? 'right' : 'left', 'label' => ''];
$data['$dir'] = ['value' => in_array(optional($this->company->language())->locale, ['ar', 'he']) ? 'rtl' : 'ltr', 'label' => ''];
$data['$dir_text_align'] = ['value' => in_array(optional($this->company->language())->locale, ['ar', 'he']) ? 'right' : 'left', 'label' => ''];
$data['$payment.date'] = ['value' => '&nbsp;', 'label' => ctrans('texts.payment_date')];
$data['$method'] = ['value' => '&nbsp;', 'label' => ctrans('texts.method')];

View File

@ -0,0 +1,66 @@
<?php
use App\Models\Language;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddHebrewLanguage extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Language::unguard();
if(!Language::find(33)) {
$serbian = ['id' => 33, 'name' => 'Serbian', 'locale' => 'sr'];
Language::create($serbian);
}
if(!Language::find(34)) {
$slovak = ['id' => 34, 'name' => 'Slovak', 'locale' => 'sk'];
Language::create($slovak);
}
if(!Language::find(35)) {
$estonia = ['id' => 35, 'name' => 'Estonian', 'locale' => 'et'];
Language::create($estonia);
}
if(!Language::find(36)) {
$bulgarian = ['id' => 36, 'name' => 'Bulgarian', 'locale' => 'bg'];
Language::create($bulgarian);
}
if(!Language::find(37)) {
$hebrew = ['id' => 37, 'name' => 'Hebrew', 'locale' => 'he'];
Language::create($hebrew);
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}

View File

@ -4716,6 +4716,8 @@ $LANG = array(
'archive_task_status' => 'Archive Task Status',
'delete_task_status' => 'Delete Task Status',
'restore_task_status' => 'Restore Task Status',
'lang_Hebrew' => 'Hebrew',
);
return $LANG;

View File

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

View File

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

View File

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

View File

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

4716
resources/lang/he/texts.php Normal file

File diff suppressed because it is too large Load Diff

View File

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