Compare commits
125 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
107bb774f6 | ||
|
|
24d473ddab | ||
|
|
94435d9820 | ||
|
|
e5fdd3d345 | ||
|
|
e5dc2b82b5 | ||
|
|
7efde8651f | ||
|
|
3255a089c4 | ||
|
|
3f82a92221 | ||
|
|
af8a18bb8f | ||
|
|
6aca5dd3d7 | ||
|
|
64c8583dfc | ||
|
|
1c292023ea | ||
|
|
cfe7e1a778 | ||
|
|
e07780af67 | ||
|
|
729127fa28 | ||
|
|
ede3aa889c | ||
|
|
d640238082 | ||
|
|
3a49f0543c | ||
|
|
43a89a03a0 | ||
|
|
9e3cde59dd | ||
|
|
a549f5a8a5 | ||
|
|
ddb9c3fd59 | ||
|
|
c2d70b841a | ||
|
|
f5e5bc2362 | ||
|
|
c43f5220e1 | ||
|
|
608d420062 | ||
|
|
bebb0b5026 | ||
|
|
c56aed023d | ||
|
|
ccf2fde716 | ||
|
|
55012e8985 | ||
|
|
714df38f4b | ||
|
|
f58b55efbf | ||
|
|
7fd2068e77 | ||
|
|
61acab1cb1 | ||
|
|
39f95895ae | ||
|
|
791862202f | ||
|
|
ac26d7ff21 | ||
|
|
c21919e141 | ||
|
|
0e3f299228 | ||
|
|
a458e5fd75 | ||
|
|
7d60149a45 | ||
|
|
47d2f3e5a7 | ||
|
|
c7bc5713f5 | ||
|
|
a3b97ff5be | ||
|
|
46f75d216d | ||
|
|
4affcef601 | ||
|
|
bd8da4cbe7 | ||
|
|
5f6236e24e | ||
|
|
e7c5480fc8 | ||
|
|
db03f10b97 | ||
|
|
e38c3b4e4c | ||
|
|
82202efb3c | ||
|
|
e6a3f429e9 | ||
|
|
c79d0d5137 | ||
|
|
4bb31c7aa4 | ||
|
|
b94ca32ebc | ||
|
|
9cba6891ef | ||
|
|
f8a6bf967b | ||
|
|
6616aeb0c1 | ||
|
|
13f7e2ee02 | ||
|
|
ab9cee6303 | ||
|
|
869b45ca8a | ||
|
|
ced27969bc | ||
|
|
87e694895a | ||
|
|
721e700ec2 | ||
|
|
2b131028bd | ||
|
|
f903fc97d7 | ||
|
|
20e4084361 | ||
|
|
6061721fa5 | ||
|
|
c3a1a38cfe | ||
|
|
21aeaa34c0 | ||
|
|
5c618533a2 | ||
|
|
cd0f1fdd76 | ||
|
|
9ea02d5bda | ||
|
|
ba4aa3e001 | ||
|
|
baba0fc4aa | ||
|
|
c2a06ec828 | ||
|
|
e0aefec165 | ||
|
|
4ee7a0749e | ||
|
|
9db75e5b22 | ||
|
|
35aab2df1f | ||
|
|
cb6778adb3 | ||
|
|
f0a7869052 | ||
|
|
f0c046ad6b | ||
|
|
746cc4d8eb | ||
|
|
e2b6aa1d30 | ||
|
|
c9c7752d2f | ||
|
|
303b80fab2 | ||
|
|
c05c124a5d | ||
|
|
1266665702 | ||
|
|
a88f61686f | ||
|
|
60159fdfb9 | ||
|
|
85d7015157 | ||
|
|
df4f4d360e | ||
|
|
96b231f7d9 | ||
|
|
98767fdfa2 | ||
|
|
deec0ea4d7 | ||
|
|
97d546effa | ||
|
|
d31d2c26e2 | ||
|
|
4490eddfb5 | ||
|
|
8580e4c9d4 | ||
|
|
8ee2127b74 | ||
|
|
3994a8df68 | ||
|
|
13859604e1 | ||
|
|
bba427242c | ||
|
|
d538d98bd3 | ||
|
|
0c96300587 | ||
|
|
a43a840d4b | ||
|
|
649c7b08c1 | ||
|
|
8a56fa108e | ||
|
|
504bde8f2d | ||
|
|
f19111bcf6 | ||
|
|
1f40699a7b | ||
|
|
ba2e8c76a8 | ||
|
|
a9c2b57bc0 | ||
|
|
d2f43a8bdd | ||
|
|
7967841935 | ||
|
|
c4031c62e5 | ||
|
|
bb116a0327 | ||
|
|
1e9dbc7c06 | ||
|
|
3f08a381ff | ||
|
|
74799c2b1d | ||
|
|
0511f31a01 | ||
|
|
2a1d095e71 | ||
|
|
c13ef55eee |
|
|
@ -3,6 +3,7 @@ APP_ENV=local
|
|||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
APP_DOMAIN=
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
|
||||
|
|
@ -37,7 +38,6 @@ CAFEL_PASSWORD=
|
|||
MAIL_INVALID_CAFEL_DATA=equipe.web@ldc.fr
|
||||
MAIL_INVALID_CAFEL_DATA_IMAGE=equipe.web@ldc.fr
|
||||
MAIL_INVALID_XML=equipe.web@ldc.fr
|
||||
MAIL_LIST_SERVICEWEB=equipe.web@ldc.fr
|
||||
|
||||
## LDC WEB STATUS CHECKER
|
||||
LDC_STATUS_CHECKER_API_KEY="MY_KEY"
|
||||
|
|
@ -45,7 +45,9 @@ LDC_STATUS_CHECKER_UUID="UUID_PROJECT"
|
|||
## LDC WEB ADMIN SECURE
|
||||
LDC_WEB_API_KEY="MY_KEY"
|
||||
|
||||
|
||||
## GOOGLE
|
||||
ANALYTICS_GOOGLE_ID=
|
||||
GOOGLE_MAP_API_KEY=
|
||||
|
||||
# TERRE D'ACTION MODAL (YYYY-MM-DD)
|
||||
TERRE_ACTION_START_DATE=
|
||||
TERRE_ACTION_END_DATE=
|
||||
|
|
|
|||
1
.gitignore
vendored
|
|
@ -18,3 +18,4 @@ Homestead.json
|
|||
Homestead.yaml
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
auth.json
|
||||
|
|
@ -1,46 +1,12 @@
|
|||
image: $CI_REGISTRY/service-web-lab/ldc-web-images-docker/ldcweb-qa:php7.3-1.0
|
||||
include:
|
||||
- project: 'ldc-web/shared-ci'
|
||||
ref: 'main'
|
||||
file: 'lint/lint7.3.yml'
|
||||
- project: 'ldc-web/shared-ci'
|
||||
ref: 'main'
|
||||
file: 'security/security7.3.yml'
|
||||
|
||||
|
||||
stages:
|
||||
- Security
|
||||
- CodingStandards
|
||||
|
||||
composer-security:
|
||||
stage: Security
|
||||
script:
|
||||
- local-php-security-checker --format=json --path=./composer.lock > composer-security-checker-report.json
|
||||
artifacts:
|
||||
when: on_failure
|
||||
expose_as: 'composer-security-checker'
|
||||
paths:
|
||||
- composer-security-checker-report.json
|
||||
allow_failure: true
|
||||
|
||||
npm-security:
|
||||
stage: Security
|
||||
script:
|
||||
- audit-ci -p npm -o json > npm-security-checker-report.json
|
||||
artifacts:
|
||||
when: on_failure
|
||||
expose_as: 'npm-security-checker'
|
||||
paths:
|
||||
- npm-security-checker-report.json
|
||||
allow_failure: true
|
||||
|
||||
phpcs:
|
||||
stage: CodingStandards
|
||||
before_script:
|
||||
- composer config gitlab-token.gitlab.com $CI_DEPLOY_USER $CI_DEPLOY_PASSWORD
|
||||
- composer install
|
||||
cache:
|
||||
paths:
|
||||
- vendor/
|
||||
script:
|
||||
- vendor/bin/phpcs --report=junit --report-file=phpcs-report.xml
|
||||
artifacts:
|
||||
when: on_failure
|
||||
expose_as: 'phpcs'
|
||||
paths:
|
||||
- phpcs-report.xml
|
||||
reports:
|
||||
junit: phpcs-report.xml
|
||||
allow_failure: false
|
||||
- lint
|
||||
- security
|
||||
|
|
|
|||
11
.gitlab/issue_templates/bug.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
## Comportement constaté
|
||||
|
||||
|
||||
## Comportement attendu
|
||||
|
||||
|
||||
## Solution envisagée
|
||||
|
||||
|
||||
## Étapes pour la reproduction du bug
|
||||
*
|
||||
7
.gitlab/issue_templates/feature.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
## Présentation du besoin
|
||||
|
||||
|
||||
## Implémentation
|
||||
|
||||
|
||||
## Maquettes, documentations...
|
||||
3
.vscode/settings.json
vendored
|
|
@ -16,7 +16,8 @@
|
|||
"titleBar.activeBackground": "#02514e",
|
||||
"titleBar.activeForeground": "#e7e7e7",
|
||||
"titleBar.inactiveBackground": "#02514e99",
|
||||
"titleBar.inactiveForeground": "#e7e7e799"
|
||||
"titleBar.inactiveForeground": "#e7e7e799",
|
||||
"commandCenter.border": "#e7e7e799"
|
||||
},
|
||||
"peacock.remoteColor": "#02514e"
|
||||
}
|
||||
|
|
|
|||
38
app/Console/Commands/CafelPoultryMepCommand.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\CafelMepPoultryJob;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class CafelPoultryMepCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'cafel:mep_poultry';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Syncronisation manuelle Cafel (/api/ldc/mepvolailles)';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->info('Running the Job, this could take some time.');
|
||||
|
||||
$job = new CafelMepPoultryJob();
|
||||
$job->handle();
|
||||
|
||||
$this->info('Fin du traitement');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
/*
|
||||
* Command Name: LDC Web Status Checker
|
||||
* Description: Envoi des infos Serveur/Laravel vers LDC Web
|
||||
* Version: 1.0
|
||||
* Author: Vincent BRIDIER
|
||||
* Author URI: vincent.bridier@ldc.fr
|
||||
*/
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class LDCWebStatusChecker extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'ldcweb:statuschecker';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Envoi des infos Serveur/Laravel vers LDC Web';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$data = [];
|
||||
$data['uuid'] = config('app.project_uuid');
|
||||
|
||||
// Sitemap.xml ?
|
||||
if (file_exists(public_path() . '/sitemap.xml')) {
|
||||
$data['sitemap'] = 'true';
|
||||
} else {
|
||||
$data['sitemap'] = 'false';
|
||||
}
|
||||
|
||||
// Robots.txt ?
|
||||
if (file_exists(public_path() . '/robots.txt')) {
|
||||
$data['robots'] = 'true';
|
||||
} else {
|
||||
$data['robots'] = 'false';
|
||||
}
|
||||
|
||||
// Check logs .
|
||||
$data['logs'] = 0;
|
||||
$patherror = storage_path('/logs');
|
||||
$files = glob($patherror . '/laravel-*.log');
|
||||
if (count($files) > 0) {
|
||||
foreach ($files as $file) {
|
||||
$data['logs'] = $data['logs'] + filesize($file);
|
||||
}
|
||||
}
|
||||
|
||||
$data['code']['version'] = app()->version();
|
||||
|
||||
try {
|
||||
Http::post(
|
||||
'https://ldc-web.s-web.test/api/status-checker',
|
||||
['token' => 'CE8S52Qq7stf5k8frF4T', 'datas' => json_encode($data)]
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -30,14 +30,15 @@ class Kernel extends ConsoleKernel
|
|||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
// * Jobs cafel sur queue cafel
|
||||
$schedule->job(CafelFoodJob::class, 'cafel')->onOneServer()->everyThreeHours();
|
||||
$schedule->job(CafelBeaVolJob::class, 'cafel')->onOneServer()->everyThreeHours();
|
||||
$schedule->job(CafelMepEggJob::class, 'cafel')->onOneServer()->everyThreeHours();
|
||||
$schedule->job(CafelEggBreederJob::class, 'cafel')->onOneServer()->everyThreeHours();
|
||||
$schedule->job(CafelPoultryBreederJob::class, 'cafel')->onOneServer()->everyThreeHours();
|
||||
$schedule->job(CafelFoodJob::class, 'cafel')->onOneServer()->dailyAt('22h30');
|
||||
$schedule->job(CafelBeaVolJob::class, 'cafel')->onOneServer()->dailyAt('22h45');
|
||||
$schedule->job(CafelMepEggJob::class, 'cafel')->onOneServer()->dailyAt('23h00');
|
||||
$schedule->job(CafelEggBreederJob::class, 'cafel')->onOneServer()->dailyAt('23h15');
|
||||
$schedule->job(CafelPoultryBreederJob::class, 'cafel')->onOneServer()->dailyAt('23h30');
|
||||
|
||||
$schedule->job(XmlFluxEggJob::class, 'tracea')->onOneServer()->dailyAt('02:00');
|
||||
$schedule->job(XmlFluxPoultryJob::class, 'tracea')->onOneServer()->dailyAt('22:00');
|
||||
$schedule->command('xml:clean_olds')->onOneServer()->dailyAt('06:00');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ namespace App\Exceptions;
|
|||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Throwable;
|
||||
use Kwaadpepper\ExceptionHandler\Exceptions\ExceptionHandler;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Sentry\Laravel\Integration;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
|
|
@ -27,18 +27,19 @@ class Handler extends ExceptionHandler
|
|||
];
|
||||
|
||||
/**
|
||||
* Report or log an exception.
|
||||
* Register the exception handling callbacks for the application.
|
||||
*
|
||||
* @param \Throwable $exception
|
||||
* @return void
|
||||
*/
|
||||
public function report(Throwable $exception)
|
||||
public function register()
|
||||
{
|
||||
if ($exception instanceof CafelApiImageFetchException) {
|
||||
$this->reportCafelApiImageErrorException($exception);
|
||||
return;
|
||||
}
|
||||
parent::report($exception);
|
||||
$this->reportable(function (\Throwable $e) {
|
||||
if ($e instanceof CafelApiImageFetchException) {
|
||||
$this->reportCafelApiImageErrorException($e);
|
||||
return;
|
||||
}
|
||||
Integration::captureUnhandledException($e);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class EggController extends Controller
|
|||
$month = $date[1];
|
||||
|
||||
$moba = TraceaEgg::where('ede_code', '=', $code)
|
||||
->whereDate('dcr', Carbon::createFromDate(null, $month, $day)->toDate())
|
||||
->where('dcr', Carbon::createFromDate(null, $month, $day)->format('Y-m-d'))
|
||||
->orderBy('box_code', 'DESC')->first();
|
||||
|
||||
if (!$moba) {
|
||||
|
|
@ -49,7 +49,7 @@ class EggController extends Controller
|
|||
$mobas = TraceaEgg::where('box_code', $id)->orderBy('box_code', 'DESC')->first();
|
||||
|
||||
if (!$mobas) {
|
||||
return redirect('/search');
|
||||
return redirect()->route('egg.search');
|
||||
}
|
||||
|
||||
$edes = $mobas->code_edes;
|
||||
|
|
@ -65,7 +65,7 @@ class EggController extends Controller
|
|||
}
|
||||
|
||||
$datePonte = $mobas->laying_date;
|
||||
$date_emballage = $mobas->date_emballage;
|
||||
$date_emballage = $mobas->packing_date;
|
||||
// * Compare DCR et Today
|
||||
$date_dcr = $mobas->dcr;
|
||||
$date_today = Carbon::now();
|
||||
|
|
@ -84,8 +84,11 @@ class EggController extends Controller
|
|||
|
||||
$inuavs = $eleveurs->pluck('inuavs')->flatten(1);
|
||||
|
||||
$mep = CafelEggMiseEnPlace::whereIn('inuav_code', $inuavs)
|
||||
->where('transfert_date', '<', $datePonte)
|
||||
$mep = CafelEggMiseEnPlace::query();
|
||||
collect($inuavs)->map(function ($inuav) use ($mep) {
|
||||
$mep->where('inuav_codes', 'LIKE', "%{$inuav}%");
|
||||
});
|
||||
$mep = $mep->where('transfert_date', '<', $datePonte)
|
||||
->orderBy('transfert_date', 'DESC')->first();
|
||||
|
||||
if ($mep) {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Fo\Ajax\GetDistributionRequest;
|
||||
use App\Http\Requests\Fo\SearchPoultryTraceaRequest;
|
||||
use App\Models\TraceaPoultry;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
|
@ -68,14 +70,34 @@ class TraceaPoultryController extends Controller
|
|||
\redirect()->route('poultry.search')->throwResponse();
|
||||
}
|
||||
|
||||
$distributionPicture = $this->getDistributionPicture($traceaPoultry->sign);
|
||||
// ! Test that breeder, food and mep are available
|
||||
if (!$traceaPoultry->mep or !$traceaPoultry->food or !$traceaPoultry->breeder) {
|
||||
return \view('front.poultry.unavailable');
|
||||
}
|
||||
|
||||
return view('front.poultry.show', compact(
|
||||
'traceaPoultry',
|
||||
'distributionPicture'
|
||||
'traceaPoultry'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Distribution Info
|
||||
*
|
||||
* @param \App\Http\Requests\Fo\Ajax\GetDistributionRequest $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getDistribution(GetDistributionRequest $request): JsonResponse
|
||||
{
|
||||
/** @var \App\Models\TraceaPoultry */
|
||||
$traceaPoultry = TraceaPoultry::where('order_num', $request->ordernum)
|
||||
->where('external_code_lot', $request->codelot)->firstOrFail();
|
||||
return \response()->json([
|
||||
'exp_date' => $traceaPoultry->exp_date,
|
||||
'sign' => $traceaPoultry->sign,
|
||||
'picture' => $this->getDistributionPicture($traceaPoultry->sign)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get distribution sign picture name if exists.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class SecureHeaders
|
|||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
"style-src 'self' $cssDev https://fonts.googleapis.com;",
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
"script-src 'self' $jsDev https://fonts.googleapis.com;"
|
||||
"script-src 'self' $jsDev https://fonts.googleapis.com https://www.googletagmanager.com;"
|
||||
];
|
||||
$response->headers->set(
|
||||
'Content-Security-Policy',
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ class TrustHosts extends Middleware
|
|||
public function hosts()
|
||||
{
|
||||
return [
|
||||
\config('app.egg_domain'),
|
||||
$this->allSubdomainsOfApplicationUrl(),
|
||||
];
|
||||
}
|
||||
|
|
|
|||
31
app/Http/Requests/Fo/Ajax/GetDistributionRequest.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Fo\Ajax;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class GetDistributionRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'codelot' => 'required|numeric|digits:10',
|
||||
'ordernum' => 'required|numeric|digits:6',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ class RemoveOldXmlEntries
|
|||
}
|
||||
try {
|
||||
$q = TraceaEgg::query();
|
||||
$q->where('dcr', '<=', now()->subMonths(config('tracea.keepEggMonths', 12)))->destroy();
|
||||
$q->where('dcr', '<=', now()->subMonths(config('tracea.keepEggMonths', 12)));
|
||||
$q->delete();
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ abstract class XArcadiaFlux implements ShouldQueue
|
|||
{
|
||||
if ($this->console) {
|
||||
$this->progressBar = $this->console->getOutput()
|
||||
->createProgressBar($total - 1);
|
||||
->createProgressBar($total);
|
||||
$this->progressBar->start();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class XmlFluxEggJob extends XmlJobs
|
|||
'code_boite' => 'box_code',
|
||||
'code_ede' => 'ede_code',
|
||||
'date_de_ponte' => 'laying_date',
|
||||
'date_emballage' => 'packing_date',
|
||||
'code_produit' => 'product_code',
|
||||
'lib_produit' => 'product_label',
|
||||
'lot_externe' => 'external_lot',
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use Illuminate\Support\Facades\File;
|
|||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
abstract class XmlJobs extends XArcadiaFlux
|
||||
{
|
||||
|
|
@ -174,7 +175,25 @@ abstract class XmlJobs extends XArcadiaFlux
|
|||
),
|
||||
LogType::critical()
|
||||
);
|
||||
$this->sendInvalidXmlEmail($filename, $e);
|
||||
$this->sendInvalidXmlEmail(
|
||||
$filename,
|
||||
$e->getPrevious()->getMessage(),
|
||||
$e->getPrevious()
|
||||
);
|
||||
$this->moveToInvalid($filename);
|
||||
continue;
|
||||
} catch (ValidationException $e) {
|
||||
$message = $e->getMessage();
|
||||
$this->log(
|
||||
sprintf(
|
||||
'File %s could not be parsed => %s on line %d',
|
||||
$filename,
|
||||
$message,
|
||||
$e->getLine()
|
||||
),
|
||||
LogType::critical()
|
||||
);
|
||||
$this->sendInvalidXmlEmail($filename, $e->getMessage(), $e);
|
||||
$this->moveToInvalid($filename);
|
||||
continue;
|
||||
} catch (AbortXmlImportException $e) {
|
||||
|
|
@ -187,6 +206,8 @@ abstract class XmlJobs extends XArcadiaFlux
|
|||
),
|
||||
LogType::error()
|
||||
);
|
||||
$this->sendInvalidXmlEmail($filename, $e->getMessage(), $e);
|
||||
$this->moveToInvalid($filename);
|
||||
report($e);
|
||||
continue;
|
||||
// * ignore the file
|
||||
|
|
@ -365,12 +386,12 @@ abstract class XmlJobs extends XArcadiaFlux
|
|||
* Send invalid XML email
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $message
|
||||
* @param \Throwable $e
|
||||
* @return void
|
||||
*/
|
||||
protected function sendInvalidXmlEmail(string $filename, \Throwable $e)
|
||||
protected function sendInvalidXmlEmail(string $filename, string $message, \Throwable $e)
|
||||
{
|
||||
$message = $e->getPrevious()->getMessage();
|
||||
Mail::send('mails.invalidxml', [
|
||||
'strError' => sprintf(
|
||||
'File %s could not be parsed => %s on line %d',
|
||||
|
|
@ -379,7 +400,7 @@ abstract class XmlJobs extends XArcadiaFlux
|
|||
$e->getLine()
|
||||
),
|
||||
'filename' => $filename,
|
||||
'exception' => $e->getPrevious()
|
||||
'exception' => $e
|
||||
], function ($m) {
|
||||
$m->to(
|
||||
config('mail.contactsList.invalidXml'),
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ namespace App\Jobs;
|
|||
use App\Exceptions\CafelApiException;
|
||||
use App\Exceptions\CafelApiImageFetchException;
|
||||
use App\Lib\CafelApi\Models\CafelEggBreeder as ApiCafelEggBreeder;
|
||||
use App\Lib\ToolboxHelper;
|
||||
use App\Models\CafelEggBreeder;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class CafelEggBreederJob extends CafelJobs
|
||||
{
|
||||
|
|
@ -16,6 +18,16 @@ class CafelEggBreederJob extends CafelJobs
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
// ! We have to remove all breeders to reimport them all in order to make sure
|
||||
// ! to delete breeders that dont exists anymore (Api fetch constrain)
|
||||
// ! vu avec Sylvain 27/10/2022
|
||||
// * Destroy breeder one by one to trigger destroy event
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\CafelEggBreeder> */
|
||||
$eggBreeders = CafelEggBreeder::all();
|
||||
$eggBreeders->each(function (CafelEggBreeder $breeder) {
|
||||
$breeder->deleteOrFail();
|
||||
});
|
||||
|
||||
$this->syncWithCafelApi(
|
||||
ApiCafelEggBreeder::class,
|
||||
'cafel.ldc.eleveursoeufs',
|
||||
|
|
@ -41,8 +53,23 @@ class CafelEggBreederJob extends CafelJobs
|
|||
) : null;
|
||||
} catch (CafelApiImageFetchException | CafelApiException $e) {
|
||||
report($e);
|
||||
$row['path_picture_1'] = null;
|
||||
}
|
||||
$validationException = ValidationException::withMessages([
|
||||
'path_picture_1' => $e->getMessage()
|
||||
]);
|
||||
|
||||
ToolboxHelper::useReflectionToUpdateProperty(
|
||||
$validationException->validator,
|
||||
'data',
|
||||
['path_picture_1' => $row['path_picture_1']]
|
||||
);
|
||||
ToolboxHelper::useReflectionToUpdateProperty(
|
||||
$validationException->validator,
|
||||
'failedRules',
|
||||
['path_picture_1' => $e->getMessage()]
|
||||
);
|
||||
|
||||
throw $validationException;
|
||||
}//end try
|
||||
try {
|
||||
$row['path_picture_2'] = !empty($row['path_picture_2']) ?
|
||||
ApiCafelEggBreeder::fetchPicture(
|
||||
|
|
@ -51,8 +78,23 @@ class CafelEggBreederJob extends CafelJobs
|
|||
) : null;
|
||||
} catch (CafelApiImageFetchException | CafelApiException $e) {
|
||||
report($e);
|
||||
$row['path_picture_2'] = null;
|
||||
}
|
||||
$validationException = ValidationException::withMessages([
|
||||
'path_picture_2' => $e->getMessage()
|
||||
]);
|
||||
|
||||
ToolboxHelper::useReflectionToUpdateProperty(
|
||||
$validationException->validator,
|
||||
'data',
|
||||
['path_picture_2' => $row['path_picture_2']]
|
||||
);
|
||||
ToolboxHelper::useReflectionToUpdateProperty(
|
||||
$validationException->validator,
|
||||
'failedRules',
|
||||
['path_picture_2' => $e->getMessage()]
|
||||
);
|
||||
|
||||
throw $validationException;
|
||||
}//end try
|
||||
|
||||
foreach (['exploitation', 'aboutyou', 'vocation', 'likeinjob', 'loue_means'] as $fieldName) {
|
||||
$row[$fieldName] = !empty($row[$fieldName]) ? $row[$fieldName] : null;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
namespace App\Jobs;
|
||||
|
||||
use App\Lib\CafelApi\Models\CafelClientModel;
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
|
|
@ -70,12 +72,26 @@ abstract class CafelJobs implements ShouldQueue
|
|||
try {
|
||||
$saveCallback($row);
|
||||
} catch (ValidationException $e) {
|
||||
/** @var \Illuminate\Validation\Validator $validator */
|
||||
$validator = $e->validator;
|
||||
/** @var array<string,integer|string> */
|
||||
$failed = $validator->invalid();
|
||||
$this->invalidRows[] = collect($row)->put('validation_message', collect($e->errors())
|
||||
->mapWithKeys(function (array $messages, string $attribute) {
|
||||
return [$attribute => collect($messages)->implode(', ')];
|
||||
->mapWithKeys(function (array $messages, string $attribute) use ($failed) {
|
||||
$verifiedValue = '';
|
||||
if (array_key_exists($attribute, $failed)) {
|
||||
$verifiedValue = ' Valeur vérifiée : ' . \json_encode($failed[$attribute]);
|
||||
}
|
||||
return [
|
||||
$attribute => collect($messages)->implode(', ') . $verifiedValue
|
||||
];
|
||||
})->implode(' '))->all();
|
||||
}
|
||||
}
|
||||
} catch (ConnectException | RequestException $e) {
|
||||
// ! Guzzle SSL Error connection failure
|
||||
\report($e);
|
||||
$this->invalidRows[] = collect($row)->put('validation_message', $e->getMessage())->all();
|
||||
}//end try
|
||||
}//end foreach
|
||||
} while (!empty($result));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@ class CafelMepEggJob extends CafelJobs
|
|||
'dateFin' => now()->format('Y-m-d')
|
||||
],
|
||||
function (array $row) {
|
||||
// * Explode inuav
|
||||
if (\array_key_exists('inuav_codes', $row)) {
|
||||
$row['inuav_codes'] = explode(',', $row['inuav_codes']);
|
||||
}
|
||||
|
||||
// * Validate row data
|
||||
CafelMepEgg::validateDataRow($row);
|
||||
|
||||
|
|
|
|||
54
app/Jobs/CafelMepPoultryJob.php
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Lib\CafelApi\Models\CafelMepPoultry;
|
||||
use App\Models\CafelPoultryMiseEnPlace;
|
||||
|
||||
class CafelMepPoultryJob extends CafelJobs
|
||||
{
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$dateDebut = now()->subDays(config('cafel.mises_en_places_retain', 370));
|
||||
$this->syncWithCafelApi(
|
||||
CafelMepPoultry::class,
|
||||
'cafel.ldc.mepvolailles',
|
||||
[
|
||||
'dateDebut' => $dateDebut->format('Y-m-d'),
|
||||
'dateFin' => now()->format('Y-m-d')
|
||||
],
|
||||
function (array $row) {
|
||||
// * Explode inuav
|
||||
if (\array_key_exists('inuav_codes', $row)) {
|
||||
$row['inuav_codes'] = explode(',', $row['inuav_codes']);
|
||||
}
|
||||
|
||||
// * Validate row data
|
||||
CafelMepPoultry::validateDataRow($row);
|
||||
|
||||
/** @var array Unique Key columns */
|
||||
$uniqueColumnsKey = [];
|
||||
foreach (CafelMepPoultry::UNIQUE_COLUMN_KEYS as $uField) {
|
||||
$uniqueColumnsKey[$uField] = $row[$uField];
|
||||
}
|
||||
|
||||
forward_static_call_array(
|
||||
[CafelPoultryMiseEnPlace::class, 'updateOrCreate'],
|
||||
[$uniqueColumnsKey, $row]
|
||||
);
|
||||
}
|
||||
);
|
||||
$this->mailInvalidRows(CafelMepPoultry::UNIQUE_COLUMN_KEYS, CafelMepPoultry::class);
|
||||
|
||||
// * DeleteOld MEPs
|
||||
// * Garder une interstice de X jours entre la suppression et ce qu'on récupère de CAFEL
|
||||
CafelPoultryMiseEnPlace::whereDate('transfert_date', '<', $dateDebut->subDays(
|
||||
config('cafel.mises_en_places_retain', 370)
|
||||
))->delete();
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,9 @@ namespace App\Jobs;
|
|||
use App\Exceptions\CafelApiException;
|
||||
use App\Exceptions\CafelApiImageFetchException;
|
||||
use App\Lib\CafelApi\Models\CafelPoultryBreeder as ApiCafelPoultryBreeder;
|
||||
use App\Lib\ToolboxHelper;
|
||||
use App\Models\CafelPoultryBreeder;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class CafelPoultryBreederJob extends CafelJobs
|
||||
{
|
||||
|
|
@ -16,6 +18,16 @@ class CafelPoultryBreederJob extends CafelJobs
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
// ! We have to remove all breeders to reimport them all in order to make sure
|
||||
// ! to delete breeders that dont exists anymore (Api fetch constrain)
|
||||
// ! vu avec Sylvain 27/10/2022
|
||||
// * Destroy breeder one by one to trigger destroy event
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\CafelEggBreeder> */
|
||||
$poultryBreeders = CafelPoultryBreeder::all();
|
||||
$poultryBreeders->each(function (CafelPoultryBreeder $breeder) {
|
||||
$breeder->deleteOrFail();
|
||||
});
|
||||
|
||||
$this->syncWithCafelApi(
|
||||
ApiCafelPoultryBreeder::class,
|
||||
'cafel.ldc.eleveursvolailles',
|
||||
|
|
@ -41,8 +53,23 @@ class CafelPoultryBreederJob extends CafelJobs
|
|||
) : null;
|
||||
} catch (CafelApiImageFetchException | CafelApiException $e) {
|
||||
report($e);
|
||||
$row['path_picture_1'] = null;
|
||||
}
|
||||
$validationException = ValidationException::withMessages([
|
||||
'path_picture_1' => $e->getMessage()
|
||||
]);
|
||||
|
||||
ToolboxHelper::useReflectionToUpdateProperty(
|
||||
$validationException->validator,
|
||||
'data',
|
||||
['path_picture_1' => $row['path_picture_1']]
|
||||
);
|
||||
ToolboxHelper::useReflectionToUpdateProperty(
|
||||
$validationException->validator,
|
||||
'failedRules',
|
||||
['path_picture_1' => $e->getMessage()]
|
||||
);
|
||||
|
||||
throw $validationException;
|
||||
}//end try
|
||||
try {
|
||||
$row['path_picture_2'] = !empty($row['path_picture_2']) ?
|
||||
ApiCafelPoultryBreeder::fetchPicture(
|
||||
|
|
@ -51,8 +78,23 @@ class CafelPoultryBreederJob extends CafelJobs
|
|||
) : null;
|
||||
} catch (CafelApiImageFetchException | CafelApiException $e) {
|
||||
report($e);
|
||||
$row['path_picture_2'] = null;
|
||||
}
|
||||
$validationException = ValidationException::withMessages([
|
||||
'path_picture_2' => $e->getMessage()
|
||||
]);
|
||||
|
||||
ToolboxHelper::useReflectionToUpdateProperty(
|
||||
$validationException->validator,
|
||||
'data',
|
||||
['path_picture_2' => $row['path_picture_2']]
|
||||
);
|
||||
ToolboxHelper::useReflectionToUpdateProperty(
|
||||
$validationException->validator,
|
||||
'failedRules',
|
||||
['path_picture_2' => $e->getMessage()]
|
||||
);
|
||||
|
||||
throw $validationException;
|
||||
}//end try
|
||||
|
||||
foreach (['issue_1', 'issue_2'] as $fieldName) {
|
||||
$row[$fieldName] = !empty($row[$fieldName]) ? $row[$fieldName] : null;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,11 @@ abstract class CafelBeaVol extends CafelClientModel
|
|||
// Eg Score A .
|
||||
'bea_code' => 'required|string|min:2|max:10',
|
||||
// Eg 19377/0 .
|
||||
'batch_code' => 'required|max:10|regex:/^[0-9A-Z]*\/\d$/',
|
||||
'batch_code' => [
|
||||
'required',
|
||||
'max:10',
|
||||
'regex:/^[0-9A-Z]+\/(?:\d|[A-Z])$/',
|
||||
],
|
||||
'last_audit_date' => 'required|date_format:Y-m-d'
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ abstract class CafelClientModel implements \JsonSerializable
|
|||
* @return array
|
||||
* @throws \Illuminate\Validation\ValidationException If data does not validate.
|
||||
*/
|
||||
protected function validateData(array $data, array $rules): array
|
||||
protected static function validateData(array $data, array $rules): array
|
||||
{
|
||||
return Validator::validate($data, $rules);
|
||||
}
|
||||
|
|
@ -228,15 +228,25 @@ abstract class CafelClientModel implements \JsonSerializable
|
|||
// * Filter Keys using intersection
|
||||
\extract(\array_intersect_key($response->body, ['Ext' => '', 'Name' => '', 'Data' => '']));
|
||||
|
||||
// * Create temp file and get its absolute path
|
||||
if (!($tempFile = tmpfile())) {
|
||||
new \RuntimeException('Could not create temp file');
|
||||
}
|
||||
|
||||
return ToolboxHelper::storeImage(
|
||||
$filePath = ToolboxHelper::storeImage(
|
||||
$folder,
|
||||
FileHelper::fromBase64(
|
||||
$tempFile,
|
||||
Str::lower($Name),
|
||||
Str::lower($Ext),
|
||||
$Data
|
||||
),
|
||||
false
|
||||
);
|
||||
|
||||
// * Closing the file will cause to remove it from temp dir!
|
||||
fclose($tempFile);
|
||||
|
||||
return $filePath;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ abstract class CafelEggBreeder extends CafelClientModel
|
|||
* @var array
|
||||
*/
|
||||
public const UNIQUE_COLUMN_KEYS = [
|
||||
'cafel_code'
|
||||
'cafel_code', 'ede_code'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -43,7 +43,7 @@ abstract class CafelEggBreeder extends CafelClientModel
|
|||
* 2 chiffres qui représentent le numéro d’ordre de chaque atelier dans une même exploitation
|
||||
* eg : 1FRZFC01
|
||||
*/
|
||||
'ede_code' => 'required|regex:/[0-3][A-Z]{5}\d\d/',
|
||||
'ede_code' => 'required|regex:/^[0-3][A-Z]{5}\d\d$/',
|
||||
// Valeurs possibles pour civility : 1 M, 2 MME, 3 EUX, 4 ELLES .
|
||||
'civility' => ['required', [EnumIsValidRule::class, BreederCivilty::class]],
|
||||
'lastname' => 'required|string|min:1|max:255',
|
||||
|
|
|
|||
|
|
@ -28,7 +28,11 @@ abstract class CafelFood extends CafelClientModel
|
|||
// 1 Pondeuse ou 2 Poulet .
|
||||
'food_type' => ['required', [EnumIsValidRule::class, FoodType::class]],
|
||||
// Eg 19377/0 .
|
||||
'batch_code' => 'required|max:10|regex:/^[0-9A-Z]*\/\d$/',
|
||||
'batch_code' => [
|
||||
'required',
|
||||
'max:10',
|
||||
'regex:/^[0-9A-Z]+\/(?:\d|[A-Z])$/',
|
||||
],
|
||||
'delivery_date' => 'required|date_format:Y-m-d'
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -22,10 +22,16 @@ abstract class CafelMepEgg extends CafelClientModel
|
|||
* @var array
|
||||
*/
|
||||
protected static $validationRules = [
|
||||
// Eg V072FXT (un seul ou plusieurs separe par une virgule).
|
||||
'inuav_codes' => 'required|array',
|
||||
// Eg V072FXT (un seul par ligne).
|
||||
'inuav_code' => 'required|string|regex:/^[A-Z]\d{3}[A-Z]{3}$/',
|
||||
'inuav_codes.*' => 'required|string|regex:/^[A-Z]\d{3}[A-Z]{3}$/',
|
||||
// Eg 19377/0 .
|
||||
'batch_code' => 'required|max:10|regex:/^[0-9A-Z]*\/\d$/',
|
||||
'batch_code' => [
|
||||
'required',
|
||||
'max:10',
|
||||
'regex:/^[0-9A-Z]+\/(?:\d|[A-Z])$/',
|
||||
],
|
||||
'transfert_date' => 'required|date_format:Y-m-d'
|
||||
];
|
||||
|
||||
|
|
@ -35,7 +41,7 @@ abstract class CafelMepEgg extends CafelClientModel
|
|||
* @var array
|
||||
*/
|
||||
protected static $columnsTranslations = [
|
||||
'Inuav_code' => 'inuav_code',
|
||||
'Inuav_code' => 'inuav_codes',
|
||||
'Batch_code' => 'batch_code',
|
||||
'Transfert_date' => 'transfert_date'
|
||||
];
|
||||
|
|
|
|||
48
app/Lib/CafelApi/Models/CafelMepPoultry.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\CafelApi\Models;
|
||||
|
||||
/**
|
||||
* @author Jérémy Munsch <jeremy.munsch@ldc.fr>
|
||||
*/
|
||||
abstract class CafelMepPoultry extends CafelClientModel
|
||||
{
|
||||
/**
|
||||
* Unique columns key
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public const UNIQUE_COLUMN_KEYS = [
|
||||
'batch_code'
|
||||
];
|
||||
|
||||
/**
|
||||
* Validation rules from cafel Api
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $validationRules = [
|
||||
// Eg V072FXT (un seul ou plusieurs separe par une virgule).
|
||||
'inuav_codes' => 'required|array',
|
||||
// Eg V072FXT (un seul par ligne).
|
||||
'inuav_codes.*' => 'required|string|regex:/^[A-Z]\d{3}[A-Z]{3}$/',
|
||||
// Eg 19377/0 .
|
||||
'batch_code' => [
|
||||
'required',
|
||||
'max:10',
|
||||
'regex:/^[0-9A-Z]+\/(?:\d|[A-Z])$/',
|
||||
],
|
||||
'transfert_date' => 'required|date_format:Y-m-d'
|
||||
];
|
||||
|
||||
/**
|
||||
* Column translations
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $columnsTranslations = [
|
||||
'Inuav_code' => 'inuav_codes',
|
||||
'Batch_code' => 'batch_code',
|
||||
'Transfert_date' => 'transfert_date'
|
||||
];
|
||||
}
|
||||
|
|
@ -105,7 +105,7 @@ class ApiInterface
|
|||
*
|
||||
* @param \App\Lib\CafelApi\Transport\Request $request
|
||||
* @return \App\Lib\CafelApi\Transport\Response
|
||||
* @throws \App\Exceptions\CafelApiException If reponse status is KO.
|
||||
* @throws \App\Exceptions\CafelApiException If reponse status is KO or not Json.
|
||||
*/
|
||||
public function call(Request $request): Response
|
||||
{
|
||||
|
|
@ -122,8 +122,9 @@ class ApiInterface
|
|||
/**
|
||||
* Process request
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @param \App\Lib\CafelApi\Transport\Request $request
|
||||
* @return \App\Lib\CafelApi\Transport\Response
|
||||
* @throws \App\Exceptions\CafelApiException If HTTP response body in not JSON.
|
||||
*/
|
||||
private function processRequest(Request $request): Response
|
||||
{
|
||||
|
|
@ -136,13 +137,13 @@ class ApiInterface
|
|||
$status = in_array($response->getStatusCode(), [200, 201]) ?
|
||||
ApiStatus::OK() : ApiStatus::KO();
|
||||
|
||||
return new Response($status, $response);
|
||||
return new Response($status, $response, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add spécific headers to the request
|
||||
*
|
||||
* @param Request $request
|
||||
* @param \App\Lib\CafelApi\Transport\Request $request
|
||||
* @return void
|
||||
*/
|
||||
private function setHeaders(Request &$request): void
|
||||
|
|
|
|||
|
|
@ -56,9 +56,10 @@ class Response
|
|||
*
|
||||
* @param \App\Enums\ApiStatus $status
|
||||
* @param \Psr\Http\Message\ResponseInterface $response
|
||||
* @param \App\Lib\CafelApi\Transport\Request $request
|
||||
* @throws \App\Exceptions\CafelApiException If HTTP response body in not JSON.
|
||||
*/
|
||||
public function __construct(ApiStatus $status, ResponseInterface $response)
|
||||
public function __construct(ApiStatus $status, ResponseInterface $response, Request $request)
|
||||
{
|
||||
$this->response = $response;
|
||||
$this->status = $status;
|
||||
|
|
@ -74,9 +75,18 @@ class Response
|
|||
// * Body should be json data.
|
||||
if (($decodedJson = $this->tryDecodeJson($this->body->getContents())) === false) {
|
||||
if (in_array(config('app.env'), ['testing', 'local'])) {
|
||||
dump((string)$this->body);
|
||||
dump(
|
||||
'should have been json',
|
||||
$this->httpCode,
|
||||
$this->status,
|
||||
$this->headers,
|
||||
$request->uri,
|
||||
(string)$this->body
|
||||
);
|
||||
}
|
||||
throw new CafelApiException('The Api should have returned JSON data');
|
||||
throw new CafelApiException(
|
||||
"The Api should have returned JSON data '{$request->uri}'"
|
||||
);
|
||||
}
|
||||
$this->body = $decodedJson;
|
||||
|
||||
|
|
|
|||
190
app/Lib/ExceptionsHelper.php
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib;
|
||||
|
||||
class ExceptionsHelper
|
||||
{
|
||||
/**
|
||||
* Handle sentry event
|
||||
*
|
||||
* @param \Sentry\Event $event
|
||||
* @return null|\Sentry\Event
|
||||
*/
|
||||
public static function sentryEventHandler(\Sentry\Event $event): ?\Sentry\Event
|
||||
{
|
||||
// Remove unwanted reports.
|
||||
$event->setModules([]);
|
||||
$event->setOsContext(null);
|
||||
|
||||
/** @var \Sentry\ExceptionDataBag[] */
|
||||
$exceptionBag = [];
|
||||
foreach ($event->getExceptions() as $exceptionDataBag) {
|
||||
$exceptionBag[] = self::getAnonymizedSentryException($exceptionDataBag);
|
||||
}
|
||||
$event->setExceptions($exceptionBag);
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonimize Sentry Exception bag
|
||||
*
|
||||
* @param \Sentry\ExceptionDataBag $exceptionDataBag
|
||||
* @return \Sentry\ExceptionDataBag
|
||||
*/
|
||||
private static function getAnonymizedSentryException(
|
||||
\Sentry\ExceptionDataBag $exceptionDataBag
|
||||
): \Sentry\ExceptionDataBag {
|
||||
$exceptionDataBag->setValue(self::getAnonymizedMessage($exceptionDataBag->getValue()));
|
||||
if ($stackTrace = $exceptionDataBag->getStacktrace()) {
|
||||
$exceptionDataBag->setStacktrace(self::getAnonymizedSentryStackTrace($stackTrace));
|
||||
}
|
||||
return $exceptionDataBag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymise sentry stacktrace
|
||||
*
|
||||
* @param \Sentry\Stacktrace $stackTrace
|
||||
* @return \Sentry\Stacktrace
|
||||
*/
|
||||
private static function getAnonymizedSentryStackTrace(\Sentry\Stacktrace $stackTrace): \Sentry\Stacktrace
|
||||
{
|
||||
/** @var \Sentry\Frame[] */
|
||||
$frames = \array_reverse($stackTrace->getFrames(), true);
|
||||
$i = \count($frames) - 1;
|
||||
// * Remove all but keep first (index.php).
|
||||
while ($i-- > 0) {
|
||||
$stackTrace->removeFrame(count($stackTrace->getFrames()) - 1);
|
||||
}
|
||||
foreach ($frames as $index => $frame) {
|
||||
$frame->setPostContext([]);
|
||||
$frame->setPreContext([]);
|
||||
$frame->setContextLine('');
|
||||
$frame->setVars(self::getAnonymizedSentryParams($frame->getVars()));
|
||||
$stackTrace->addFrame($frame);
|
||||
if ($index === 0) {
|
||||
$stackTrace->removeFrame(count($stackTrace->getFrames()) - 1);
|
||||
}
|
||||
}
|
||||
return $stackTrace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get anonymized sentry params
|
||||
*
|
||||
* @param mixed[] $params
|
||||
* @return string[]
|
||||
*/
|
||||
private static function getAnonymizedSentryParams(array $params): array
|
||||
{
|
||||
foreach ($params as &$param) {
|
||||
$type = \strtolower(\gettype($param));
|
||||
if (\is_string($param)) {
|
||||
$type = \explode(' ', \trim($param))[0] ?? null;
|
||||
}
|
||||
switch ($type) {
|
||||
case 'Lambda':
|
||||
case 'Object':
|
||||
continue 2;
|
||||
case 'array':
|
||||
$param = sprintf('Array(%d)', \count($param));
|
||||
continue 2;
|
||||
default:
|
||||
if (\is_numeric($param)) {
|
||||
$param = \ucfirst($type);
|
||||
continue 2;
|
||||
}
|
||||
if (\is_string($param)) {
|
||||
$param = sprintf('String(%d)', \strlen($param));
|
||||
continue 2;
|
||||
}
|
||||
} //end switch
|
||||
} //end foreach
|
||||
return $params;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Anonymize at least Sql queries
|
||||
*
|
||||
* @param string $message
|
||||
* @return string
|
||||
*/
|
||||
public static function getAnonymizedMessage(string $message): string
|
||||
{
|
||||
$message = \preg_replace('/^(.*)( \(SQL:.*\))$/', '$1', $message) ?? $message;
|
||||
if ($sqlPos = \strpos($message, 'to use near')) {
|
||||
$message = \mb_strcut($message, 0, $sqlPos);
|
||||
}
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymize stack trace
|
||||
*
|
||||
* @param \Throwable $e
|
||||
* @return string
|
||||
*/
|
||||
public static function getAnonymizedStackTrace(\Throwable $e): string
|
||||
{
|
||||
$projectPath = \realpath(\sprintf('%s/../', \app_path()));
|
||||
$traceStack = $e->getTrace();
|
||||
$traceStr = '';
|
||||
$maxStackStage = 0;
|
||||
foreach ($traceStack as $stackStage => $stack) {
|
||||
$maxStackStage = $stackStage;
|
||||
$traceStr .= \sprintf(
|
||||
'#%s %s(%d): ',
|
||||
$stackStage,
|
||||
str_replace($projectPath, '', $stack['file'] ?? ''),
|
||||
$stack['line'] ?? ''
|
||||
);
|
||||
if (isset($stack['class'])) {
|
||||
$traceStr .= "{$stack['class']}->{$stack['function']}(";
|
||||
if (isset($stack['args'])) {
|
||||
$traceStr .= self::handleArgs($stack);
|
||||
}
|
||||
$traceStr .= ")\n";
|
||||
} elseif (isset($stack['function'])) {
|
||||
$traceStr .= "{$stack['function']}(";
|
||||
if (isset($stack['args'])) {
|
||||
$traceStr .= self::handleArgs($stack);
|
||||
}
|
||||
$traceStr .= ")\n";
|
||||
}
|
||||
} //end foreach
|
||||
$maxStackStage++;
|
||||
$traceStr .= "#$maxStackStage {main}";
|
||||
return $traceStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Args
|
||||
*
|
||||
* @param array $stack
|
||||
* @return string
|
||||
*/
|
||||
public static function handleArgs(array $stack): string
|
||||
{
|
||||
$traceArgs = '';
|
||||
$argsCount = count($stack['args']);
|
||||
for ($i = 0; $i < $argsCount; $i++) {
|
||||
$type = \gettype($stack['args'][$i]);
|
||||
switch ($type) {
|
||||
case 'object':
|
||||
$traceArgs .= sprintf('Object(%s)', \get_class($stack['args'][$i]));
|
||||
break;
|
||||
case 'array':
|
||||
$traceArgs .= sprintf('Array(%d)', \count($stack['args'][$i]));
|
||||
break;
|
||||
case 'string':
|
||||
$traceArgs .= sprintf('String(%d)', \strlen($stack['args'][$i]));
|
||||
break;
|
||||
default:
|
||||
$traceArgs .= \gettype($stack['args'][$i]);
|
||||
}
|
||||
$traceArgs .= ($i !== ($argsCount - 1) ? ',' : '');
|
||||
}
|
||||
return $traceArgs;
|
||||
}
|
||||
}
|
||||
|
|
@ -51,21 +51,18 @@ class FileHelper
|
|||
}
|
||||
|
||||
/**
|
||||
* Generate from blob
|
||||
* Generate from base64 blob
|
||||
*
|
||||
* @param string $fileName
|
||||
* @param string $extension
|
||||
* @param string $base64String
|
||||
* @param resource $tempFile A temp file where to store data.
|
||||
* @param string $fileName The target filename.
|
||||
* @param string $extension The file extension to use.
|
||||
* @param string $base64String The base64 encode picture.
|
||||
* @return SplFileInfo
|
||||
* @throws \ErrorException If writing to temp file failed.
|
||||
* @throws \App\Exceptions\CafelApiImageFetchException If invalid image was given or ext could not be confirmed.
|
||||
*/
|
||||
public static function fromBase64(string $fileName, string $extension, string $base64String): SplFileInfo
|
||||
public static function fromBase64($tempFile, string $fileName, string $extension, string $base64String): SplFileInfo
|
||||
{
|
||||
// * Create temp file and get its absolute path
|
||||
if (!($tempFile = tmpfile())) {
|
||||
new \ErrorException('Could not create temp file');
|
||||
}
|
||||
$tempFilePath = stream_get_meta_data($tempFile)['uri'];
|
||||
|
||||
if (!($blob = \base64_decode($base64String, true))) {
|
||||
|
|
@ -93,12 +90,6 @@ class FileHelper
|
|||
throw new \ErrorException('Could not write on temp file');
|
||||
}
|
||||
|
||||
// Close this file after response is sent.
|
||||
// Closing the file will cause to remove it from temp director!
|
||||
app()->terminating(function () use ($tempFile) {
|
||||
fclose($tempFile);
|
||||
});
|
||||
|
||||
return new SplFileInfo(\storage_path("tmp/$filePath.$extension"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,23 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|||
|
||||
abstract class ToolboxHelper
|
||||
{
|
||||
/**
|
||||
* Update any prop using reflexion
|
||||
*
|
||||
* @param object $object
|
||||
* @param string $property
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
* @throws \ReflectionException If the class or property does not exist.
|
||||
*/
|
||||
public static function useReflectionToUpdateProperty(object &$object, string $property, $value)
|
||||
{
|
||||
$refProperty = new \ReflectionProperty(\get_class($object), $property);
|
||||
$refProperty->setAccessible(true);
|
||||
$refProperty->setValue($object, $value);
|
||||
$refProperty->setAccessible(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an image of different types
|
||||
*
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ namespace App\Models;
|
|||
use App\Enums\BreederCivilty;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Kwaadpepper\Enum\Traits\CastsEnums;
|
||||
|
||||
|
|
@ -97,7 +99,8 @@ class CafelEggBreeder extends Model
|
|||
{
|
||||
// * EVENT CLOSURES.
|
||||
static::creating(function (self $model) {
|
||||
return self::areInuavCodesUniques($model);
|
||||
self::areInuavCodesUniques($model);
|
||||
self::isEdeCodeUnique($model);
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
if ($model->getRawOriginal('path_picture_1') !== $model->path_picture_1) {
|
||||
|
|
@ -106,7 +109,16 @@ class CafelEggBreeder extends Model
|
|||
if ($model->getRawOriginal('path_picture_2') !== $model->path_picture_2) {
|
||||
Storage::delete(\public_path($model->getRawOriginal('path_picture_2')));
|
||||
}
|
||||
return self::areInuavCodesUniques($model);
|
||||
self::areInuavCodesUniques($model);
|
||||
self::isEdeCodeUnique($model);
|
||||
});
|
||||
static::deleting(function (self $model) {
|
||||
if ($model->getRawOriginal('path_picture_1')) {
|
||||
Storage::delete(\public_path($model->getRawOriginal('path_picture_1')));
|
||||
}
|
||||
if ($model->getRawOriginal('path_picture_2')) {
|
||||
Storage::delete(\public_path($model->getRawOriginal('path_picture_2')));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -137,26 +149,44 @@ class CafelEggBreeder extends Model
|
|||
/**
|
||||
* Check if inuav codes are unique
|
||||
*
|
||||
* @param self $eleveur
|
||||
* @param self $breeder
|
||||
* @return boolean
|
||||
* @throws \Illuminate\Validation\ValidationException If inuav code is already used.
|
||||
*/
|
||||
protected static function areInuavCodesUniques(self $eleveur): bool
|
||||
protected static function areInuavCodesUniques(self $breeder): bool
|
||||
{
|
||||
$q = self::query();
|
||||
// * Update condition
|
||||
$q->where(function ($q) use ($eleveur) {
|
||||
foreach ($eleveur->inuavs as $inuav) {
|
||||
$q->orWhere('inuavs', 'LIKE', "%$inuav%");
|
||||
$q->where(function ($q) use ($breeder) {
|
||||
foreach ($breeder->inuavs as $inuav) {
|
||||
$q->orWhere('inuavs', '=', $inuav);
|
||||
}
|
||||
});
|
||||
if ($eleveur->cafel_code) {
|
||||
$q->where('cafel_code', '!=', $eleveur->cafel_code);
|
||||
if ($breeder->cafel_code) {
|
||||
$q->where('cafel_code', '!=', $breeder->cafel_code);
|
||||
}
|
||||
if ($q->count()) {
|
||||
throw ValidationException::withMessages(['inuavs' => 'Les codes INUAVS doinvent être uniques'
|
||||
throw ValidationException::withMessages([
|
||||
'inuavs' => 'Les codes INUAVS doinvent être uniques : ' . collect($breeder->inuavs)->implode(',')
|
||||
]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if ede code is unique
|
||||
*
|
||||
* @param self $breeder
|
||||
* @return boolean
|
||||
* @throws \Illuminate\Validation\ValidationException If ede code is already used.
|
||||
*/
|
||||
protected static function isEdeCodeUnique(self $breeder): bool
|
||||
{
|
||||
Validator::make([
|
||||
'ede_code' => $breeder->ede_code
|
||||
], ['ede_code' => [
|
||||
Rule::unique($breeder->getTable(), 'ede_code')->ignore($breeder->id)
|
||||
]])->validate();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ class CafelEggMiseEnPlace extends Model
|
|||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'transfert_date' => 'date'
|
||||
'transfert_date' => 'date',
|
||||
'inuav_codes' => 'array'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -43,7 +44,7 @@ class CafelEggMiseEnPlace extends Model
|
|||
*/
|
||||
protected $fillable = [
|
||||
'batch_code',
|
||||
'inuav_code',
|
||||
'inuav_codes',
|
||||
'transfert_date'
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,14 @@ class CafelPoultryBreeder extends Model
|
|||
}
|
||||
return self::areInuavCodesUniques($model);
|
||||
});
|
||||
static::deleting(function (self $model) {
|
||||
if ($model->getRawOriginal('path_picture_1')) {
|
||||
Storage::delete(\public_path($model->getRawOriginal('path_picture_1')));
|
||||
}
|
||||
if ($model->getRawOriginal('path_picture_2')) {
|
||||
Storage::delete(\public_path($model->getRawOriginal('path_picture_2')));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
|
@ -119,7 +127,7 @@ class CafelPoultryBreeder extends Model
|
|||
}
|
||||
if ($q->count()) {
|
||||
throw ValidationException::withMessages([
|
||||
'inuavs' => 'Les codes INUAVS doinvent être uniques'
|
||||
'inuavs' => 'Les codes INUAVS doinvent être uniques : ' . collect($breeder->inuavs)->implode(',')
|
||||
]);
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
70
app/Models/CafelPoultryMiseEnPlace.php
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class CafelPoultryMiseEnPlace extends Model
|
||||
{
|
||||
/**
|
||||
* The primary key for the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'batch_code';
|
||||
|
||||
/**
|
||||
* Indicates if the IDs are auto-incrementing.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $incrementing = false;
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'transfert_date' => 'date',
|
||||
'inuav_codes' => 'array'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'batch_code',
|
||||
'inuav_codes',
|
||||
'transfert_date'
|
||||
];
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Get Mep using cafel lot code
|
||||
*
|
||||
* @param integer $codeLotCafel
|
||||
* @return self|null
|
||||
*/
|
||||
public static function whereCodeLotCafel(int $codeLotCafel): ?self
|
||||
{
|
||||
return Cache::remember("poultryMep$codeLotCafel", 5, function () use ($codeLotCafel) {
|
||||
return self::where(
|
||||
'batch_code',
|
||||
'LIKE',
|
||||
'%' . \filter_var($codeLotCafel, \FILTER_SANITIZE_STRING) . '/%'
|
||||
)->first();
|
||||
});
|
||||
}
|
||||
}
|
||||
11
app/Models/PoultryPackshot.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class PoultryPackshot extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
}
|
||||
|
|
@ -37,6 +37,7 @@ class TraceaEgg extends Model
|
|||
'box_code',
|
||||
'ede_code',
|
||||
'laying_date',
|
||||
'packing_date',
|
||||
'product_code',
|
||||
'product_label',
|
||||
'external_lot',
|
||||
|
|
@ -50,6 +51,7 @@ class TraceaEgg extends Model
|
|||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'packing_date' => 'date',
|
||||
'laying_date' => 'date',
|
||||
'dcr' => 'date'
|
||||
];
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use App\Traits\HasCompositePrimaryKey;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class TraceaPoultry extends Model
|
||||
{
|
||||
|
|
@ -70,6 +71,22 @@ class TraceaPoultry extends Model
|
|||
'prep_date' => 'date'
|
||||
];
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
// * EVENT CLOSURES.
|
||||
static::creating(function (self $model) {
|
||||
self::hasAtLeastOneBarCode($model);
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::hasAtLeastOneBarCode($model);
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
|
|
@ -81,10 +98,10 @@ class TraceaPoultry extends Model
|
|||
{
|
||||
$family = Str::upper($this->getAttributeFromArray('family'));
|
||||
switch (true) {
|
||||
case \strpos($family, 'LABEL') !== false:
|
||||
case \strpos($family, 'LOUE') !== false:
|
||||
return PoultryLabelType::labelRouge();
|
||||
case \strpos($family, 'BIO') !== false:
|
||||
return PoultryLabelType::labelRouge();
|
||||
return PoultryLabelType::bio();
|
||||
default:
|
||||
return PoultryLabelType::unkown();
|
||||
}
|
||||
|
|
@ -98,6 +115,7 @@ class TraceaPoultry extends Model
|
|||
public function getBreederAttribute(): ?CafelPoultryBreeder
|
||||
{
|
||||
$matches = [];
|
||||
|
||||
preg_match('/(?P<inuav>V\d{3}[A-Z]{3})/', \strval($this->breeder_code), $matches);
|
||||
if (!\array_key_exists('inuav', $matches)) {
|
||||
return collect();
|
||||
|
|
@ -153,4 +171,53 @@ class TraceaPoultry extends Model
|
|||
// * On utilise code lot_opa vue que son explication de merde est inversée ... Uu
|
||||
return CafelFood::whereCodeLotCafel(FoodType::chicken(), \intval($this->opa_lot));
|
||||
}
|
||||
|
||||
/**
|
||||
* * Get Bea
|
||||
*
|
||||
* L'explication du batch code est un non sens.... putin de merde
|
||||
*
|
||||
* Comment faisons-nous pour lier notre lot à une note BEA ?
|
||||
* (code lot sous ce format : XXXXX/0 pour les données BEA) -> Code lot CAFEL / Code OPA
|
||||
* Comment faisons-nous pour lier notre lot à son alimentation ?
|
||||
* (code lot sous ce format : XXXXX/0 pour les données alimentation) -> Code lot CAFEL / Code OPA
|
||||
* Pour ces questions, peux-tu nous dire avec les informations que nous recevons du flux Sablé
|
||||
* les règles que nous devons utiliser stp ? * -> @Mathilde Hervier peux-tu répondre à cette question ?
|
||||
* Le 6e champ reçu dans le fichier xml est le code lot OPA qui sert donc à faire le lien avec la CAFEL
|
||||
*
|
||||
* @return \App\Models\CafelPoultryMiseEnPlace|null
|
||||
*/
|
||||
public function getMepAttribute(): ?CafelPoultryMiseEnPlace
|
||||
{
|
||||
// * On utilise code lot_opa vue que son explication de merde est inversée ... Uu
|
||||
return CafelPoultryMiseEnPlace::whereCodeLotCafel(\intval($this->opa_lot));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert has at least one barcode
|
||||
*
|
||||
* @param self $tracea
|
||||
* @return boolean
|
||||
* @throws \Illuminate\Validation\ValidationException If inuav code is already used.
|
||||
*/
|
||||
protected static function hasAtLeastOneBarCode(self $tracea): bool
|
||||
{
|
||||
if (empty($tracea->barcode_price) and empty($tracea->barcode_weight)) {
|
||||
throw ValidationException::withMessages([
|
||||
'barcode_price' => "Il faut au moins un code barre pour faire la recherche '{$tracea->barcode_price}'",
|
||||
'barcode_weight' => "Il faut au moins un code barre pour faire la recherche '{$tracea->barcode_weight}'"
|
||||
]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Packshot
|
||||
*
|
||||
* @return \App\Models\PoultryPackshot|null
|
||||
*/
|
||||
public function getPackshotAttribute(): ?PoultryPackshot
|
||||
{
|
||||
return PoultryPackshot::whereItemCode($this->item_code)->first();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
26
app/Providers/ViewServiceProvider.php
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class ViewServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
if (!app()->runningInConsole()) {
|
||||
View::share('isDisplayedTAModal', (function () {
|
||||
$now = now();
|
||||
return $now->greaterThanOrEqualTo(new Carbon(config('modal.terreActionStartDate'))) &&
|
||||
$now->lessThanOrEqualTo(new Carbon(config('modal.terreActionEndDate')));
|
||||
})());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"gitlab-token": {
|
||||
"gitlab.com": "glpat-gbNVMUd6T2kaB5eii7TZ"
|
||||
}
|
||||
}
|
||||
|
|
@ -17,24 +17,26 @@
|
|||
"fideloper/proxy": "^4.0",
|
||||
"guzzlehttp/guzzle": "^7.4",
|
||||
"kwaadpepper/enum": "^2.1",
|
||||
"kwaadpepper/exception-handler": "^0.0.6",
|
||||
"kwaadpepper/refresh-sitemap": "^1.0",
|
||||
"laravel/framework": "^8.0",
|
||||
"laravel/tinker": "^2.0",
|
||||
"laravel/ui": "^3.0",
|
||||
"laravelcollective/html": "^6.0",
|
||||
"ldc/web-admin-secure-laravel": "1.0.1",
|
||||
"ldc/web-status-checker-laravel": "1.0.3",
|
||||
"ldc/web-admin-secure-laravel": "^1.0",
|
||||
"ldc/web-status-checker-laravel": "^1.0",
|
||||
"mews/purifier": "^3.3",
|
||||
"nesbot/carbon": "^2.29",
|
||||
"sentry/sentry-laravel": "^3.1",
|
||||
"spatie/laravel-mix-preload": "^1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"facade/ignition": "^2.3.6",
|
||||
"fzaninotto/faker": "^1.4",
|
||||
"laravel/ui": "^3.0",
|
||||
"mockery/mockery": "^1.0",
|
||||
"facade/ignition": "^2.5",
|
||||
"fakerphp/faker": "^1.9.1",
|
||||
"laravel/sail": "^1.0.1",
|
||||
"mockery/mockery": "^1.4.2",
|
||||
"nunomaduro/collision": "^5.0",
|
||||
"phpunit/phpunit": "^9.0",
|
||||
"phpunit/phpunit": "^9.3.3",
|
||||
"slevomat/coding-standard": "^7.0"
|
||||
},
|
||||
"config": {
|
||||
|
|
@ -43,7 +45,10 @@
|
|||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
},
|
||||
"gitlab-domains": [
|
||||
"lab.s-web.fr"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
|
|
@ -77,9 +82,9 @@
|
|||
]
|
||||
},
|
||||
"repositories": {
|
||||
"gitlab.com/16669037": {
|
||||
"lab.s-web.fr": {
|
||||
"type": "composer",
|
||||
"url": "https://gitlab.com/api/v4/group/16669037/-/packages/composer/packages.json"
|
||||
"url": "https://lab.s-web.fr/api/v4/group/23/-/packages/composer/packages.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2873
composer.lock
generated
|
|
@ -53,6 +53,8 @@ return [
|
|||
*/
|
||||
|
||||
'url' => env('APP_URL', 'http://localhost'),
|
||||
'domain' => env('APP_DOMAIN', 'tracabilite.loue.fr'),
|
||||
'egg_domain' => env('APP_EGG_DOMAIN', 'bo.gt'),
|
||||
|
||||
'asset_url' => env('ASSET_URL', null),
|
||||
|
||||
|
|
@ -175,6 +177,7 @@ return [
|
|||
App\Providers\AuthServiceProvider::class,
|
||||
App\Providers\EventServiceProvider::class,
|
||||
App\Providers\RouteServiceProvider::class,
|
||||
App\Providers\ViewServiceProvider::class,
|
||||
|
||||
],
|
||||
|
||||
|
|
@ -234,7 +237,4 @@ return [
|
|||
'CafelPoultryBreeder' => \App\Models\CafelPoultryBreeder::class,
|
||||
|
||||
],
|
||||
|
||||
'project_uuid' => env('PROJECT_UUID'),
|
||||
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
// ! Food et MEp sont requis pour afficher un resultat traca volaille
|
||||
// * How many days should we retain Aliment
|
||||
'food_retain' => 30,
|
||||
'food_retain' => 370,
|
||||
// * How many days should we retain MEP (egg)
|
||||
'mises_en_places_retain' => 370,
|
||||
'client_version' => '1.0',
|
||||
|
|
@ -51,6 +52,12 @@ return [
|
|||
'methods' => [
|
||||
'GET'
|
||||
]
|
||||
],
|
||||
'cafel.ldc.mepvolailles' => [
|
||||
'uri' => 'api/ldc/mepvolailles',
|
||||
'methods' => [
|
||||
'GET'
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
/**
|
||||
* Send mail when app debug is turn off
|
||||
* so you can be warned if an unhandled exception occurs
|
||||
*/
|
||||
'enableMaiLog' => !config('app.debug'),
|
||||
|
||||
/**
|
||||
* Put a developper secured mailbox in here
|
||||
* so you can receive email if things go mad
|
||||
*/
|
||||
'contactsList' => explode(',', env('MAIL_LIST_SERVICEWEB', 'equipe.web@ldc.fr')),
|
||||
];
|
||||
|
|
@ -62,9 +62,12 @@ return [
|
|||
|
||||
// * Contacts List
|
||||
'contactsList' => [
|
||||
'invalidXml' => explode(',', env('MAIL_INVALID_XML', 'equipe.web@ldc.fr')),
|
||||
'invalidCafel' => explode(',', env('MAIL_INVALID_CAFEL_DATA', 'equipe.web@ldc.fr')),
|
||||
'invalidCafelImage' => explode(',', env('MAIL_INVALID_CAFEL_DATA_IMAGE', 'equipe.web@ldc.fr')),
|
||||
'invalidXml' => preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', env('MAIL_INVALID_XML', 'equipe.web@ldc.fr')),
|
||||
'invalidCafel' => preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', env('MAIL_INVALID_CAFEL_DATA', 'equipe.web@ldc.fr')),
|
||||
'invalidCafelImage' => preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', env(
|
||||
'MAIL_INVALID_CAFEL_DATA_IMAGE',
|
||||
'equipe.web@ldc.fr'
|
||||
)),
|
||||
],
|
||||
|
||||
/*
|
||||
|
|
|
|||
6
config/modal.php
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'terreActionStartDate' => env('TERRE_ACTION_START_DATE'),
|
||||
'terreActionEndDate' => env('TERRE_ACTION_END_DATE')
|
||||
];
|
||||
62
config/sentry.php
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'dsn' => env('SENTRY_LARAVEL_DSN', env('SENTRY_DSN')),
|
||||
|
||||
// The release version of your application
|
||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')).
|
||||
'release' => env('SENTRY_RELEASE'),
|
||||
|
||||
// When left empty or `null` the Laravel environment will be used.
|
||||
'environment' => env('SENTRY_ENVIRONMENT'),
|
||||
|
||||
'breadcrumbs' => [
|
||||
// Capture Laravel logs in breadcrumbs.
|
||||
'logs' => true,
|
||||
|
||||
// Capture SQL queries in breadcrumbs.
|
||||
'sql_queries' => true,
|
||||
|
||||
// Capture bindings on SQL queries logged in breadcrumbs.
|
||||
'sql_bindings' => true,
|
||||
|
||||
// Capture queue job information in breadcrumbs.
|
||||
'queue_info' => true,
|
||||
|
||||
// Capture command information in breadcrumbs.
|
||||
'command_info' => true,
|
||||
],
|
||||
|
||||
'tracing' => [
|
||||
// Trace queue jobs as their own transactions.
|
||||
'queue_job_transactions' => env('SENTRY_TRACE_QUEUE_ENABLED', false),
|
||||
|
||||
// Capture queue jobs as spans when executed on the sync driver.
|
||||
'queue_jobs' => true,
|
||||
|
||||
// Capture SQL queries as spans.
|
||||
'sql_queries' => true,
|
||||
|
||||
// Try to find out where the SQL query originated from and add it to the query spans.
|
||||
'sql_origin' => true,
|
||||
|
||||
// Capture views as spans.
|
||||
'views' => true,
|
||||
|
||||
// Indicates if the tracing integrations supplied by Sentry should be loaded.
|
||||
'default_integrations' => true,
|
||||
|
||||
// Indicates that requests without a matching route should be traced.
|
||||
'missing_routes' => false,
|
||||
],
|
||||
|
||||
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#send-default-pii
|
||||
'send_default_pii' => env('SENTRY_SEND_DEFAULT_PII', false),
|
||||
|
||||
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#traces-sample-rate
|
||||
'traces_sample_rate' => env('SENTRY_TRACES_SAMPLE_RATE') === null ? null : (float)env('SENTRY_TRACES_SAMPLE_RATE'),
|
||||
|
||||
'before_send' => [\App\Lib\ExceptionsHelper::class, 'sentryEventHandler'],
|
||||
|
||||
];
|
||||
|
|
@ -37,6 +37,8 @@ class CreateTraceaEggsTable extends Migration
|
|||
->comment('Pas de description xs:integer [0-9]{6}|[0-9]{12}');
|
||||
$table->date('laying_date')
|
||||
->comment('Le date de ponte xs:date');
|
||||
$table->date('packing_date')
|
||||
->comment('Le date d\'emballage xs:date');
|
||||
$table->date('dcr')
|
||||
->comment('Date dcr ? xs:date');
|
||||
});
|
||||
|
|
@ -60,9 +62,9 @@ class CreateTraceaEggsTable extends Migration
|
|||
$table->renameColumn('code_boite', 'box_code');
|
||||
$table->renameColumn('ean13', 'ean_13');
|
||||
$table->renameColumn('date_ponte', 'laying_date');
|
||||
$table->renameColumn('date_emballage', 'packing_date');
|
||||
});
|
||||
Schema::table('tracea_eggs', function (Blueprint $table) {
|
||||
$table->dropColumn(['date_emballage']);
|
||||
$table->string('ede_code', 10)
|
||||
->comment('Le code EDE xs:string length 8')
|
||||
->change();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateCafelPoultryMiseEnPlacesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('cafel_poultry_mise_en_places', function (Blueprint $table) {
|
||||
$table->string('batch_code', 10)->unique();
|
||||
$table->string('inuav_code', 100);
|
||||
$table->date('transfert_date');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('cafel_poultry_mise_en_places');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddIndexesOnTracaEgg extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('tracea_eggs', function (Blueprint $table) {
|
||||
$table->index(['ede_code']);
|
||||
$table->index(['dcr']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('tracea_eggs', function (Blueprint $table) {
|
||||
$table->dropIndex(['ede_code']);
|
||||
$table->dropIndex(['dcr']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
use App\Models\CafelEggBreeder;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddUniqueOnEdeEggBreeders extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
// * Destroy breeder one by one to trigger destroy event
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\CafelEggBreeder> */
|
||||
$eggBreeders = CafelEggBreeder::all();
|
||||
$eggBreeders->each(function (CafelEggBreeder $breeder) {
|
||||
$breeder->deleteOrFail();
|
||||
});
|
||||
|
||||
Schema::table('cafel_egg_breeders', function (Blueprint $table) {
|
||||
$table->unique(['ede_code']);
|
||||
});
|
||||
Log::alert('Please reimport all egg breeders');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('cafel_egg_breeders', function (Blueprint $table) {
|
||||
$table->dropUnique(['ede_code']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class MakeMisesEnPlaceHandleMultipleInuav extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('cafel_egg_mise_en_places', function (Blueprint $table) {
|
||||
$table->renameColumn('inuav_code', 'inuav_codes');
|
||||
});
|
||||
Schema::table('cafel_poultry_mise_en_places', function (Blueprint $table) {
|
||||
$table->renameColumn('inuav_code', 'inuav_codes');
|
||||
});
|
||||
Schema::table('cafel_egg_mise_en_places', function (Blueprint $table) {
|
||||
$table->string('inuav_codes', 400)->change();
|
||||
});
|
||||
Schema::table('cafel_poultry_mise_en_places', function (Blueprint $table) {
|
||||
$table->string('inuav_codes', 400)->change();
|
||||
});
|
||||
DB::table('cafel_egg_mise_en_places')->get()
|
||||
->each(function (object $eggMep) {
|
||||
DB::table('cafel_egg_mise_en_places')
|
||||
->where('batch_code', $eggMep->batch_code)
|
||||
->update(['inuav_codes' => collect(
|
||||
explode(',', $eggMep->inuav_codes)
|
||||
)->filter()->jsonSerialize()]);
|
||||
});
|
||||
DB::table('cafel_poultry_mise_en_places')->get()
|
||||
->each(function (object $poultryMep) {
|
||||
DB::table('cafel_poultry_mise_en_places')
|
||||
->where('batch_code', $poultryMep->batch_code)
|
||||
->update(['inuav_codes' => collect(
|
||||
explode(',', $poultryMep->inuav_codes)
|
||||
)->filter()->jsonSerialize()]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
DB::table('cafel_egg_mise_en_places')->get()
|
||||
->each(function (object $eggMep) {
|
||||
DB::table('cafel_egg_mise_en_places')
|
||||
->where('batch_code', $eggMep->batch_code)
|
||||
->update(['inuav_codes' => collect(json_decode($eggMep->inuav_codes))->filter()
|
||||
->first()]);
|
||||
});
|
||||
DB::table('cafel_poultry_mise_en_places')->get()
|
||||
->each(function (object $poultryMep) {
|
||||
DB::table('cafel_poultry_mise_en_places')
|
||||
->where('batch_code', $poultryMep->batch_code)
|
||||
->update(['inuav_codes' => collect(json_decode($poultryMep->inuav_codes))->filter()
|
||||
->first()]);
|
||||
});
|
||||
Schema::table('cafel_egg_mise_en_places', function (Blueprint $table) {
|
||||
$table->string('inuav_codes', 100)->change();
|
||||
});
|
||||
Schema::table('cafel_poultry_mise_en_places', function (Blueprint $table) {
|
||||
$table->string('inuav_codes', 100)->change();
|
||||
});
|
||||
Schema::table('cafel_egg_mise_en_places', function (Blueprint $table) {
|
||||
$table->renameColumn('inuav_codes', 'inuav_code');
|
||||
});
|
||||
Schema::table('cafel_poultry_mise_en_places', function (Blueprint $table) {
|
||||
$table->renameColumn('inuav_codes', 'inuav_code');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreatePoultryPackshotsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('poultry_packshots', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('item_code', 14)->comment("Item Code = tracea_poultries.item_code");
|
||||
$table->string('ean', 13)->comment("Ean 13");
|
||||
$table->string('packshot_name')->comment("Packshot picture name");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('poultry_packshots');
|
||||
}
|
||||
}
|
||||
|
|
@ -13,5 +13,6 @@ class DatabaseSeeder extends Seeder
|
|||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->call(PoultryPackshotsTableSeeder::class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2096
database/seeders/PoultryPackshotsTableSeeder.php
Normal file
5147
package-lock.json
generated
|
|
@ -25,10 +25,8 @@
|
|||
"resolve-url-loader": "^5.0.0",
|
||||
"sass": "1.32.13",
|
||||
"sass-loader": "^8.0.2",
|
||||
"sweetalert2": "^11.4.35",
|
||||
"vue": "^2.6.14",
|
||||
"vue-template-compiler": "^2.6.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"sweetalert2": "^11.4.20"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
resources/assets/images/bea/Visuel-BEA-II---B-BIEN.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
resources/assets/images/bea/Visuel-BEA-II---C-ASSEZBIEN.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
resources/assets/images/bea/Visuel-BEA-II---D-STANDARD.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
resources/assets/images/bea/Visuel-BEA-II---E-MINIMAL.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
resources/assets/images/bea/Visuel_FDA.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
resources/assets/images/food/alimentation_label_rouge.png
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
resources/assets/images/food/terres_agricoles_locales.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
resources/assets/images/infos/etiquette-legendee-eleveur.png
Normal file
|
After Width: | Height: | Size: 629 KiB |
BIN
resources/assets/images/poire_loue.png
Normal file
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 3.5 MiB |
|
After Width: | Height: | Size: 3.6 MiB |
|
After Width: | Height: | Size: 3.3 MiB |
|
After Width: | Height: | Size: 3.6 MiB |
|
After Width: | Height: | Size: 2.9 MiB |
|
After Width: | Height: | Size: 3.9 MiB |
|
After Width: | Height: | Size: 7.6 MiB |
|
After Width: | Height: | Size: 12 MiB |
|
After Width: | Height: | Size: 12 MiB |
|
After Width: | Height: | Size: 2.9 MiB |
|
After Width: | Height: | Size: 3.1 MiB |
|
After Width: | Height: | Size: 2.7 MiB |
|
After Width: | Height: | Size: 3.6 MiB |
|
After Width: | Height: | Size: 3.9 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 3.5 MiB |
|
After Width: | Height: | Size: 3.7 MiB |
|
After Width: | Height: | Size: 3.7 MiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 3.5 MiB |
|
After Width: | Height: | Size: 3.9 MiB |
|
After Width: | Height: | Size: 4.4 MiB |
|
After Width: | Height: | Size: 3.5 MiB |
|
After Width: | Height: | Size: 3 MiB |
|
After Width: | Height: | Size: 2.9 MiB |
|
After Width: | Height: | Size: 3.7 MiB |
|
After Width: | Height: | Size: 3.9 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
|
After Width: | Height: | Size: 3.9 MiB |