Merge pull request #8421 from turbo124/v5-develop

Updated readme
This commit is contained in:
David Bomba 2023-04-02 08:48:07 +10:00 committed by GitHub
commit 2390daecea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 5287 additions and 4 deletions

View File

@ -83,6 +83,66 @@ http://localhost:8000/client/login - For Client Portal
user: user@example.com
pass: password
```
## Developers Guide
### App Design
The API and client portal have been developed using [Laravel](https://laravel.com) if you wish to contribute to this project familiarity with Laravel is essential.
When inspecting functionality of the API, the best place to start would be in the routes/api.php file which describes all of the availabe API endpoints. The controller methods then describe all the entry points into each domain of the application, ie InvoiceController / QuoteController
The average API request follows this path into the application.
* Middleware processes the request initially inspecting the domain being requested + provides the authentication layer.
* The request then passes into a Form Request (Type hinted in the controller methods) which is used to provide authorization and also validation of the request. If successful, the request is then passed into the controller method where it is digested, here is an example:
```php
public function store(StoreInvoiceRequest $request)
{
$invoice = $this->invoice_repo->save($request->all(), InvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id));
$invoice = $invoice->service()
->fillDefaults()
->triggeredActions($request)
->adjustInventory()
->save();
event(new InvoiceWasCreated($invoice, $invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
return $this->itemResponse($invoice);
}
```
Here for example we are storing a new invoice, we pass the validated request along with a factory into the invoice repository where it is processed and saved.
The returned invoice then passes through its service class (app/Services/Invoice) where various actions are performed.
A event is then fired which notifies listeners in the application (app/Providers/EventServiceProvider) which perform non blocking sub tasks
Finally the invoice is transformed (app/Transformers/) and returned as a response via Fractal.
### Developer environment
Using the Quick Hosting Setup describe above you can quickly get started building out your development environment. Instead of using
```
composer i -o --no-dev
```
use
```
composer i -o
```
This provides the developer tools including phpunit which allows the test suite to be run.
If you are considering contributing back to the main repository, please add in any tests for new functionality / modifications. This will greatly increase the chances of your PR being accepted
Also, if you plan any additions for the main repository, you may want to discuss this with us first on Slack where we can assist with any technical information and provide advice.
## Credits
* [Hillel Coren](https://hillelcoren.com/)

View File

@ -188,6 +188,8 @@ class NinjaMailerJob implements ShouldQueue
}
/* Releasing immediately does not add in the backoff */
sleep(rand(0, 3));
$this->release($this->backoff()[$this->attempts()-1]);
}

View File

@ -63,7 +63,7 @@ class WebhookSingle implements ShouldQueue
public function backoff()
{
return [10, 30, 60, 180, 3600];
return [15, 35, 65, 185, 3605];
}
/**
@ -223,6 +223,9 @@ class WebhookSingle implements ShouldQueue
$this->company,
))->handle();
//add some entropy to the retry
sleep(rand(0, 3));
$this->release($this->backoff()[$this->attempts()-1]);
}
}

View File

@ -327,7 +327,6 @@ use Laracasts\Presenter\PresentableTrait;
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Vendor> $vendors
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Webhook> $webhooks
* @property int $calculate_taxes
* @property int $tax_all_products
* @property mixed $tax_data
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $all_activities
@ -557,7 +556,6 @@ class Company extends BaseModel
'convert_expense_currency',
'notify_vendor_when_paid',
'calculate_taxes',
'tax_all_products',
];
protected $hidden = [

View File

@ -309,6 +309,9 @@ class Email implements ShouldQueue
$this->tearDown();
/* Releasing immediately does not add in the backoff */
sleep(rand(0, 3));
$this->release($this->backoff()[$this->attempts()-1]);
$message = null;

View File

@ -136,6 +136,8 @@ class EmailMailer implements ShouldQueue
/* Releasing immediately does not add in the backoff */
sleep(rand(0, 3));
$this->release($this->backoff()[$this->attempts()-1]);
$message = null;

View File

@ -194,7 +194,6 @@ class CompanyTransformer extends EntityTransformer
'notify_vendor_when_paid' => (bool) $company->notify_vendor_when_paid,
'invoice_task_hours' => (bool) $company->invoice_task_hours,
'calculate_taxes' => (bool) $company->calculate_taxes,
'tax_all_products' => (bool) $company->tax_all_products,
];
}

20
lang/fr_CH/pagination.php Normal file
View File

@ -0,0 +1,20 @@
<?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' => '&laquo; Précédent',
'next' => 'Suivant &raquo;',
];

24
lang/fr_CH/reminders.php Normal file
View File

@ -0,0 +1,24 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Password Reminder 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' => 'Les mots de passe doivent avoir au moins six caractères et doivent être identiques.',
'user' => 'Nous ne pouvons trouver cet utilisateur avec cette adresse courriel.',
'token' => "Ce jeton de réinitialisation du mot de passe n'est pas valide.",
'sent' => 'Rappel du mot de passe envoyé !',
];

5030
lang/fr_CH/texts.php Normal file

File diff suppressed because it is too large Load Diff

142
lang/fr_CH/validation.php Normal file
View File

@ -0,0 +1,142 @@
<?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
| such as the size rules. Feel free to tweak each of these messages.
|
*/
'accepted' => 'Le champ :attribute doit être accepté.',
'active_url' => "Le champ :attribute n'est pas une URL valide.",
'after' => 'Le champ :attribute doit être une date postérieure au :date.',
'alpha' => 'Le champ :attribute doit seulement contenir des lettres.',
'alpha_dash' => 'Le champ :attribute doit seulement contenir des lettres, des chiffres et des tirets.',
'alpha_num' => 'Le champ :attribute doit seulement contenir des chiffres et des lettres.',
'array' => 'Le champ :attribute doit être un tableau.',
'before' => 'Le champ :attribute doit être une date antérieure au :date.',
'between' => [
'numeric' => 'La valeur de :attribute doit être comprise entre :min et :max.',
'file' => 'Le fichier :attribute doit avoir une taille entre :min et :max kilobytes.',
'string' => 'Le texte :attribute doit avoir entre :min et :max caractères.',
'array' => 'Le champ :attribute doit avoir entre :min et :max éléments.',
],
'confirmed' => 'Le champ de confirmation :attribute ne correspond pas.',
'date' => "Le champ :attribute n'est pas une date valide.",
'date_format' => 'Le champ :attribute ne correspond pas au format :format.',
'different' => 'Les champs :attribute et :other doivent être différents.',
'digits' => 'Le champ :attribute doit avoir :digits chiffres.',
'digits_between' => 'Le champ :attribute doit avoir entre :min and :max chiffres.',
'email' => 'Le champ :attribute doit être une adresse email valide.',
'exists' => 'Le champ :attribute sélectionné est invalide.',
'image' => 'Le champ :attribute doit être une image.',
'in' => 'Le champ :attribute est invalide.',
'integer' => 'Le champ :attribute doit être un entier.',
'ip' => 'Le champ :attribute doit être une adresse IP valide.',
'max' => [
'numeric' => 'La valeur de :attribute ne peut être supérieure à :max.',
'file' => 'Le fichier :attribute ne peut être plus gros que :max kilobytes.',
'string' => 'Le texte de :attribute ne peut contenir plus de :max caractères.',
'array' => 'Le champ :attribute ne peut avoir plus de :max éléments.',
],
'mimes' => 'Le champ :attribute doit être un fichier de type : :values.',
'min' => [
'numeric' => 'La valeur de :attribute doit être supérieure à :min.',
'file' => 'Le fichier :attribute doit être plus que gros que :min kilobytes.',
'string' => 'Le texte :attribute doit contenir au moins :min caractères.',
'array' => 'Le champ :attribute doit avoir au moins :min éléments.',
],
'not_in' => "Le champ :attribute sélectionné n'est pas valide.",
'numeric' => 'Le champ :attribute doit contenir un nombre.',
'regex' => 'Le format du champ :attribute est invalide.',
'required' => 'Le champ :attribute est obligatoire.',
'required_if' => 'Le champ :attribute est obligatoire quand la valeur de :other est :value.',
'required_with' => 'Le champ :attribute est obligatoire quand :values est présent.',
'required_with_all' => 'Le champ :attribute est obligatoire quand :values est présent.',
'required_without' => "Le champ :attribute est obligatoire quand :values n'est pas présent.",
'required_without_all' => "Le champ :attribute est requis quand aucun de :values n'est présent.",
'same' => 'Les champs :attribute et :other doivent être identiques.',
'size' => [
'numeric' => 'La valeur de :attribute doit être :size.',
'file' => 'La taille du fichier de :attribute doit être de :size kilobytes.',
'string' => 'Le texte de :attribute doit contenir :size caractères.',
'array' => 'Le champ :attribute doit contenir :size éléments.',
],
'unique' => 'La valeur du champ :attribute est déjà utilisée.',
'url' => "Le format de l'URL de :attribute n'est pas valide.",
'positive' => ':attribute doit être supérieur à zero.',
'has_credit' => "Le client n'a pas un crédit suffisant.",
'notmasked' => 'Les valeurs sont masquées',
'less_than' => 'The :attribute must be less than :value',
'has_counter' => 'The value must contain {$counter}',
'valid_contacts' => 'All of the contacts must have either an email or name',
'valid_invoice_items' => 'The invoice exceeds the maximum amount',
/*
|--------------------------------------------------------------------------
| 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' => [
'name' => 'Nom',
'username' => 'Pseudo',
'email' => 'Courriel',
'first_name' => 'Prénom',
'last_name' => 'Nom',
'password' => 'Mot de passe',
'password_confirmation' => 'Confirmation du mot de passe',
'city' => 'Ville',
'country' => 'Pays',
'address' => 'Adresse',
'phone' => 'Téléphone',
'mobile' => 'Mobile',
'age' => 'Âge',
'sex' => 'Sexe',
'gender' => 'Genre',
'day' => 'Jour',
'month' => 'Mois',
'year' => 'Année',
'hour' => 'Heure',
'minute' => 'Minute',
'second' => 'Seconde',
'title' => 'Titre',
'content' => 'Contenu',
'description' => 'Description',
'excerpt' => 'Extrait',
'date' => 'Date',
'time' => 'Heure',
'available' => 'Disponible',
'size' => 'Taille',
],
];