refactor(database): improve replicated factories, seeders, and config injection

- AbstractTableFactory delegates connection resolution without hardcoded config keys
- Enforce mandatory connection parameter on Migrator without Infra dependencies
- Inject ArcadiaStorageConfig, AppConfig, and HmacAuthConfig into services, seeders, and health checkers
- Enhance factories and seeders with helper methods (truncate, count, query, new)
- Clean up covers annotations on database seeders integration tests
This commit is contained in:
Jérémy Munsch 2026-08-26 17:29:13 +02:00
parent cec8d1ea66
commit 1842223ddc
Signed by: forge-joniko
GPG key ID: D7EFE2F5CB6CC0E4
17 changed files with 830 additions and 239 deletions

View file

@ -4,19 +4,54 @@ declare(strict_types=1);
namespace Database\ArcadiaReplicate\Factories;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use Infra\Config\ArcadiaStorageConfig;
abstract class AbstractTableFactory implements TableFactory
{
/** @var list<callable(array<string, mixed>): array<string, mixed>|array<string, mixed>> */
protected array $states = [];
public function __construct(
protected string $connection
) {
protected string $connection;
public function __construct(?string $connection = null)
{
$this->connection = $connection ?? static::connectionName();
}
public static function new(string $connection): static
public static function connectionName(): string
{
return resolve(ArcadiaStorageConfig::class)->databaseConnection;
}
public static function tableName(): string
{
return static::table()::name();
}
public static function query(?string $connection = null): Builder
{
return DB::connection($connection ?? static::connectionName())
->table(static::tableName());
}
public static function count(?string $connection = null): int
{
return static::query($connection)->count();
}
public static function truncate(?string $connection = null): void
{
static::query($connection)->delete();
}
public static function deleteAll(?string $connection = null): void
{
static::truncate($connection);
}
public static function new(?string $connection = null): static
{
return new static($connection);
}
@ -58,11 +93,10 @@ abstract class AbstractTableFactory implements TableFactory
*/
public function create(array $attributes = []): array
{
$data = $this->raw($attributes);
$tableName = static::table()::name();
$data = $this->raw($attributes);
DB::connection($this->connection)
->table($tableName)
->table(static::tableName())
->insert($data);
return $data;

View file

@ -87,16 +87,18 @@ final class IncoCompoFactory extends AbstractTableFactory
return $this->state([
'ID' => 96504,
'ID_INCO' => 47789,
'NOM' => 'BQ 2 STEAKS DINDE S/ATM LG OCB',
'VAL_ENERG_KJ_R' => 522,
'VAL_ENERG_KCAL_R' => 124,
'MAT_GRASS_R' => 4.6,
'AGS_R' => 1.5,
'GLUCIDES_R' => 0.7,
'SUCRE_R' => 0.0,
'PROTEINE_R' => 20.0,
'SEL_R' => 0.18,
'NUTRI_SCORE_2022' => 'A',
'NOM' => 'NUGGETS DE POULET DU VOLAILLER LE GAULOIS',
'VAL_ENERG_KJ_R' => 890,
'VAL_ENERG_KCAL_R' => 212,
'MAT_GRASS_R' => 9.5,
'AGS_R' => 1.8,
'GLUCIDES_R' => 16.0,
'SUCRE_R' => 0.8,
'FIB_ALIM_R' => 1.5,
'PROTEINE_R' => 15.0,
'SEL_R' => 1.10,
'CLASSEMENT' => 'B',
'NUTRI_SCORE_2022' => 'B',
]);
}
@ -105,17 +107,171 @@ final class IncoCompoFactory extends AbstractTableFactory
return $this->state([
'ID' => 124503,
'ID_INCO' => 47996,
'NOM' => 'POULET FERMIER NOIR',
'VAL_ENERG_KJ_R' => 623,
'VAL_ENERG_KCAL_R' => 149,
'MAT_GRASS_R' => 7.2,
'AGS_R' => 2.0,
'NOM' => 'GESIERS ET FOIES CONFITS LE GAULOIS',
'VAL_ENERG_KJ_R' => 710,
'VAL_ENERG_KCAL_R' => 170,
'MAT_GRASS_R' => 8.5,
'AGS_R' => 2.8,
'GLUCIDES_R' => 0.5,
'SUCRE_R' => 0.2,
'PROTEINE_R' => 23.0,
'SEL_R' => 1.30,
'CLASSEMENT' => 'B',
'NUTRI_SCORE_2022' => 'B',
]);
}
public function pouletFermierLoue(): self
{
return $this->state([
'ID' => 124504,
'ID_INCO' => 4,
'NOM' => 'POULET FERMIER DE LOUE LABEL ROUGE',
'VAL_ENERG_KJ_R' => 620,
'VAL_ENERG_KCAL_R' => 148,
'MAT_GRASS_R' => 6.8,
'AGS_R' => 1.9,
'GLUCIDES_R' => 0.0,
'SUCRE_R' => 0.0,
'PROTEINE_R' => 21.0,
'SEL_R' => 0.16,
'P_SUR_L' => '2.92',
'PROTEINE_R' => 21.5,
'SEL_R' => 0.15,
'CLASSEMENT' => 'A',
'NUTRI_SCORE_2022' => 'A',
]);
}
public function cordonBleuDinde(): self
{
return $this->state([
'ID' => 130101,
'ID_INCO' => 51201,
'NOM' => 'CORDON BLEU DE DINDE MAITRE COQ',
'VAL_ENERG_KJ_R' => 1010,
'VAL_ENERG_KCAL_R' => 242,
'MAT_GRASS_R' => 12.5,
'AGS_R' => 4.2,
'GLUCIDES_R' => 18.0,
'SUCRE_R' => 1.2,
'PROTEINE_R' => 14.0,
'SEL_R' => 1.45,
'CLASSEMENT' => 'D',
'NUTRI_SCORE_2022' => 'D',
]);
}
public function lasagnesBolognaise(): self
{
return $this->state([
'ID' => 140205,
'ID_INCO' => 62305,
'NOM' => 'LASAGNES A LA BOLOGNAISE PUR BOEUF MARIE',
'VAL_ENERG_KJ_R' => 590,
'VAL_ENERG_KCAL_R' => 141,
'MAT_GRASS_R' => 5.8,
'AGS_R' => 2.5,
'GLUCIDES_R' => 13.5,
'SUCRE_R' => 2.4,
'FIB_ALIM_R' => 1.2,
'PROTEINE_R' => 8.2,
'SEL_R' => 0.78,
'CLASSEMENT' => 'B',
'NUTRI_SCORE_2022' => 'B',
]);
}
public function nemsPoulet(): self
{
return $this->state([
'ID' => 150312,
'ID_INCO' => 73412,
'NOM' => 'NEMS AU POULET TRADITION D ASIE',
'VAL_ENERG_KJ_R' => 845,
'VAL_ENERG_KCAL_R' => 202,
'MAT_GRASS_R' => 8.2,
'AGS_R' => 1.6,
'GLUCIDES_R' => 23.0,
'SUCRE_R' => 2.1,
'PROTEINE_R' => 8.5,
'SEL_R' => 1.25,
'CLASSEMENT' => 'C',
'NUTRI_SCORE_2022' => 'C',
]);
}
public function emincesPouletRoti(): self
{
return $this->state([
'ID' => 160420,
'ID_INCO' => 84520,
'NOM' => 'EMINCES DE POULET ROTI REGHALAL',
'VAL_ENERG_KJ_R' => 480,
'VAL_ENERG_KCAL_R' => 114,
'MAT_GRASS_R' => 2.1,
'AGS_R' => 0.6,
'GLUCIDES_R' => 0.8,
'SUCRE_R' => 0.5,
'PROTEINE_R' => 23.0,
'SEL_R' => 1.40,
'CLASSEMENT' => 'A',
'NUTRI_SCORE_2022' => 'A',
]);
}
public function filetCanardSudOuest(): self
{
return $this->state([
'ID' => 170502,
'ID_INCO' => 48102,
'NOM' => 'MAGRET DE CANARD DU SUD OUEST LE GAULOIS',
'VAL_ENERG_KJ_R' => 790,
'VAL_ENERG_KCAL_R' => 189,
'MAT_GRASS_R' => 11.0,
'AGS_R' => 3.8,
'GLUCIDES_R' => 0.0,
'SUCRE_R' => 0.0,
'PROTEINE_R' => 22.5,
'SEL_R' => 0.12,
'CLASSEMENT' => 'A',
'NUTRI_SCORE_2022' => 'A',
]);
}
public function aiguillettesPouletThym(): self
{
return $this->state([
'ID' => 180640,
'ID_INCO' => 52340,
'NOM' => 'AIGUILLETTES DE POULET MARINES THYM CITRON MAITRE COQ',
'VAL_ENERG_KJ_R' => 495,
'VAL_ENERG_KCAL_R' => 118,
'MAT_GRASS_R' => 2.8,
'AGS_R' => 0.5,
'GLUCIDES_R' => 0.9,
'SUCRE_R' => 0.4,
'PROTEINE_R' => 22.0,
'SEL_R' => 0.95,
'CLASSEMENT' => 'A',
'NUTRI_SCORE_2022' => 'A',
]);
}
public function gratinDauphinois(): self
{
return $this->state([
'ID' => 190750,
'ID_INCO' => 63450,
'NOM' => 'GRATIN DAUPHINOIS A LA CREME FRAICHE MARIE',
'VAL_ENERG_KJ_R' => 680,
'VAL_ENERG_KCAL_R' => 163,
'MAT_GRASS_R' => 9.8,
'AGS_R' => 6.2,
'GLUCIDES_R' => 14.2,
'SUCRE_R' => 1.8,
'FIB_ALIM_R' => 1.6,
'PROTEINE_R' => 3.8,
'SEL_R' => 0.85,
'CLASSEMENT' => 'C',
'NUTRI_SCORE_2022' => 'C',
]);
}
}

View file

@ -39,7 +39,8 @@ final class IncoFactory extends AbstractTableFactory
. 'panure : 30% (farine de BLÉ, eau, sel, levure, épices). '
. 'Huile de tournesol. Peut contenir des traces de lait.',
'NB_PORTION' => '10',
'LST_ALLERGENE' => '3,10',
'LST_ALLERGENE' => '1:Gluten;7:Lait',
'MARQUE' => 1,
'NUTRISCORE_ON_PACK' => 'B',
'PDS_NET_UVC' => 200.0,
'PDS_BRUT_UVC' => 211.0,
@ -69,28 +70,21 @@ final class IncoFactory extends AbstractTableFactory
'NO_ART' => 47789,
'DENOM_LEG' => 'Viande de poulet traitée en salaison, panée et cuite',
'DESCRIPTIF' => 'Nuggets de poulet du volailler LE GAULOIS',
'ASTUCES' => 'Pour plus de croustillance, cuisson au Air Fryer pendant 6 minutes à 200°C.',
'CONSEIL_PREPA' => 'Au four chaud pendant 10 minutes à 210°C ou à la poêle pendant 10 minutes sans ajout de matière grasse.',
'ARG_VENTE' => 'Une volaille 100% française, du blé 100% français et une recette sans conservateur.',
'ALLEGATIONS' => 'sans conservateur, sans huile de palme, volaille 100% française',
'LST_ING' => 'Viande de poulet traitée en salaison : 70% (viande de poulet : 51%, eau, '
. 'farine de BLÉ, fibre de BLÉ, sel, arômes naturels), '
. 'panure : 30% (farine de BLÉ, eau, sel, levure, épices). Huile de tournesol.',
. 'panure : 30% (farine de BLÉ, eau, sel, levure, épices). Huile de tournesol. Traces éventuelles de lait.',
'NB_PORTION' => '10',
'PDS_NET_UVC' => 200.0,
'PDS_BRUT_UVC' => 211.0,
'MARQUE' => 1,
'FAMILLE_VTE' => 31,
'PDS_NET_UVC' => 300.0,
'PDS_BRUT_UVC' => 320.0,
'NUTRISCORE_ON_PACK' => 'B',
]);
}
public function pouletFermierLoue(): self
{
return $this->state([
'NO_ART' => 4,
'DENOM_LEG' => 'Poulet fermier blanc label rouge',
'DESCRIPTIF' => 'Poulet fermier de Loué Label Rouge élevé en liberté pendant 84 jours minimum.',
'CONSEIL_PREPA' => 'A consommer cuit à cœur. Préchauffer le four à 200°C, enfourner pendant 1h30.',
'LST_ING' => 'Poulet éviscéré sans abats, bridé avec tarses coupés à la jointure (100% poulet).',
'NB_PORTION' => '4/5',
'PDS_NET_UVC' => 1400.0,
'PDS_BRUT_UVC' => 1411.0,
'NUTRISCORE_ON_PACK' => 'A',
'LST_ALLERGENE' => '1:Gluten;7:Lait',
'LST_ADDITIF' => 'E300:Acide ascorbique;E450:Diphosphates',
]);
}
@ -98,16 +92,212 @@ final class IncoFactory extends AbstractTableFactory
{
return $this->state([
'NO_ART' => 47996,
'DENOM_LEG' => 'Gésiers et foies de volaille traités en salaison, confits dans la graisse',
'DESCRIPTIF' => 'Assortiment de gésiers et de foies confits à réchauffer en 10 minutes.',
'CONSEIL_PREPA' => '10 minutes à la poêle pour des salades variées et gourmandes.',
'DENOM_LEG' => 'Gésiers et foies de volaille traités en salaison, confits dans la graisse de volaille',
'DESCRIPTIF' => 'Assortiment de gésiers et de foies confits Le Gaulois',
'ASTUCES' => 'Idéal pour agrémenter vos salades périgourdines tièdes.',
'CONSEIL_PREPA' => '10 minutes à la poêle à feu doux pour des salades variées et gourmandes.',
'ARG_VENTE' => 'Des abats nobles confits lentement dans la pure tradition volaillère.',
'ALLEGATIONS' => 'sans colorant, sans arôme artificiel',
'LST_ING' => 'Gésiers de poulet et de dinde (82%), graisse de canard (6%), sel, arômes naturels, '
. 'nitrite de sodium. Foies de poulet (89%), graisse de canard (6%), sel, romarin.',
. 'conservateur : nitrite de sodium (E250), antioxydant : érythorbate de sodium (E316). '
. 'Foies de poulet (89%), graisse de canard (6%), sel, extrait de romarin (E392).',
'NB_PORTION' => '3/4',
'PDS_NET_UVC' => 300.0,
'PDS_BRUT_UVC' => 347.0,
'MARQUE' => 1,
'FAMILLE_VTE' => 319,
'PDS_NET_UVC' => 255.0,
'PDS_BRUT_UVC' => 285.0,
'NUTRISCORE_ON_PACK' => 'B',
'LST_ADDITIF' => 'E316,E392,E250',
'LST_ADDITIF' => 'E250:Nitrite de sodium;E316:Érythorbate de sodium;E392:Extrait de romarin',
]);
}
public function pouletFermierLoue(): self
{
return $this->state([
'NO_ART' => 4,
'DENOM_LEG' => 'Poulet fermier blanc Label Rouge élevé en liberté',
'DESCRIPTIF' => 'Poulet fermier de Loué Label Rouge',
'ASTUCES' => 'Arroser régulièrement avec le jus de cuisson pour une peau croustillante.',
'CONSEIL_PREPA' => 'Au four traditionnel préchauffé à 200°C (th. 6/7) pendant 1h30 pour une volaille de 1,4 kg.',
'ARG_VENTE' => 'Élevé en plein air pendant 84 jours minimum. Alimentation 100% végétaux, minéraux et vitamines.',
'ALLEGATIONS' => 'Label Rouge, élevé en liberté 84 jours, nourri sans OGM',
'LST_ING' => 'Poulet entier prêt à cuire sans abats (100% poulet fermier de Loué).',
'NB_PORTION' => '4/5',
'MARQUE' => 3,
'FAMILLE_VTE' => 306,
'PDS_NET_UVC' => 1400.0,
'PDS_BRUT_UVC' => 1420.0,
'NUTRISCORE_ON_PACK' => 'A',
'LST_ALLERGENE' => null,
'LST_ADDITIF' => null,
]);
}
public function cordonBleuDinde(): self
{
return $this->state([
'NO_ART' => 51201,
'DENOM_LEG' => 'Préparation de viande de dinde traitée en salaison, '
. 'garnie de fromage fondu et de jambon de dinde, panée et cuite',
'DESCRIPTIF' => 'Le véritable Cordon Bleu de dinde Maître CoQ',
'ASTUCES' => 'Pour un fromage bien coulant, laissez reposer 1 minute après cuisson.',
'CONSEIL_PREPA' => 'A la poêle 12 minutes à feu doux avec une noisette de beurre, ou au four 15 minutes à 180°C.',
'ARG_VENTE' => 'Une recette généreuse avec un cœur fondant au fromage et de la volaille française.',
'ALLEGATIONS' => 'volaille française, sans huile de palme',
'LST_ING' => 'Viande de dinde (45%), panure (farine de BLÉ, eau, levure, sel, épices), '
. 'fromage fondu (15% - FROMAGE, eau, BEURRE, amidons modifiés, LACTOSÉRUM, sels de fonte : E331, E452), '
. 'jambon de dinde (10% - viande de dinde, eau, sel, dextrose, arômes naturels, conservateur : E250). '
. 'Huile de tournesol. Traces éventuelles d\'œufs, céleri, moutarde.',
'NB_PORTION' => '2',
'MARQUE' => 2,
'FAMILLE_VTE' => 31,
'PDS_NET_UVC' => 200.0,
'PDS_BRUT_UVC' => 220.0,
'NUTRISCORE_ON_PACK' => 'D',
'LST_ALLERGENE' => '1:Gluten;7:Lait;3:Œufs;9:Céleri;10:Moutarde',
'LST_ADDITIF' => 'E250:Nitrite de sodium;E331:Citrates de sodium;E452:Polyphosphates',
]);
}
public function lasagnesBolognaise(): self
{
return $this->state([
'NO_ART' => 62305,
'DENOM_LEG' => 'Lasagnes fraîches à la viande de bœuf cuisinée à la tomate et béchamel onctueuse',
'DESCRIPTIF' => 'Lasagnes à la Bolognaise pur bœuf Marie',
'ASTUCES' => 'Gratinez au four traditionnel avec une pincée d\'emmental râpé supplémentaire.',
'CONSEIL_PREPA' => 'Au four micro-ondes 7 minutes à 800W ou au four traditionnel 25 minutes à 180°C.',
'ARG_VENTE' => 'De la viande bovine 100% française, des pâtes fraîches maison et une sauce mijotée au vin blanc.',
'ALLEGATIONS' => 'Viande bovine française, sans conservateur, sans colorant',
'LST_ING' => 'Sauce bolognaise (45% - pulpe de tomates, viande de bœuf VBF : 18%, eau, oignons, carottes, '
. 'vin blanc, CÉLERI, huile d\'olive, ail, thym, laurier, sel, poivre), '
. 'pâtes fraîches (25% - semoule de BLÉ dur, eau, ŒUFS frais), '
. 'sauce béchamel (25% - eau, LAIT demi-écrémé, farine de BLÉ, BEURRE, crème fraîche, muscade, sel), '
. 'EMMENTAL râpé (5%). Traces éventuelles de poisson, crustacés.',
'NB_PORTION' => '1',
'MARQUE' => 4,
'FAMILLE_VTE' => 120,
'PDS_NET_UVC' => 350.0,
'PDS_BRUT_UVC' => 380.0,
'NUTRISCORE_ON_PACK' => 'B',
'LST_ALLERGENE' => '1:Gluten;3:Œufs;7:Lait;9:Céleri',
'LST_ADDITIF' => null,
]);
}
public function nemsPoulet(): self
{
return $this->state([
'NO_ART' => 73412,
'DENOM_LEG' => 'Pâtés impériaux au poulet et légumes avec sauce Nuoc Mâm',
'DESCRIPTIF' => 'Nems croustillants au poulet Tradition d\'Asie',
'ASTUCES' => 'Dégustez enveloppés dans une feuille de salade avec quelques feuilles de menthe fraîche.',
'CONSEIL_PREPA' => 'Au four préchauffé à 210°C pendant 12 minutes en retournant à mi-cuisson.',
'ARG_VENTE' => 'Galette de riz ultra croustillante, farce parfumée aux champignons noirs et vermicelles.',
'ALLEGATIONS' => 'Recette authentique asiatique, sans arôme artificiel',
'LST_ING' => 'Farce : 65% (viande de poulet : 30%, vermicelles de pois réhydratés, carottes, oignons, '
. 'champignons noirs réhydratés, germes de haricot mungo, sauce SOJA [eau, graines de SOJA, sel, farine de BLÉ], '
. 'huile de SÉSAME, sucre, sel, poivre), galette de riz : 35% (eau, farine de riz, huile de tournesol, sel). '
. 'Sauce Nuoc Mâm : eau, sucre, sauce POISSON (extrait de POISSON, sel), vinaigre d\'alcool.',
'NB_PORTION' => '4',
'MARQUE' => 5,
'FAMILLE_VTE' => 135,
'PDS_NET_UVC' => 280.0,
'PDS_BRUT_UVC' => 310.0,
'NUTRISCORE_ON_PACK' => 'C',
'LST_ALLERGENE' => '1:Gluten;4:Poissons;6:Soja;11:Graines de sésame',
'LST_ADDITIF' => null,
]);
}
public function emincesPouletRoti(): self
{
return $this->state([
'NO_ART' => 84520,
'DENOM_LEG' => 'Émincés de filets de poulet traités en salaison, cuits et rôtis au four - Certifié Halal',
'DESCRIPTIF' => 'Émincés de poulet rôti Réghalal',
'ASTUCES' => 'Prêts à l\'emploi dans vos wraps, sandwichs, salades césar ou fajitas.',
'CONSEIL_PREPA' => 'A consommer froid ou réchauffé 2 minutes à la poêle sans matière grasse.',
'ARG_VENTE' => '100% filet de poulet, doré au four, certifié Halal par un organisme certificateur indépendant.',
'ALLEGATIONS' => 'Certifié Halal, 100% filet, riche en protéines, sans colorant',
'LST_ING' => 'Filet de poulet Halal : 92%, eau, sel, dextrose, arôme naturel, fécule de pomme de terre, '
. 'antioxydant : ascorbate de sodium (E301). Traces éventuelles de lait, gluten, œuf.',
'NB_PORTION' => '2/3',
'MARQUE' => 6,
'FAMILLE_VTE' => 150,
'PDS_NET_UVC' => 150.0,
'PDS_BRUT_UVC' => 165.0,
'NUTRISCORE_ON_PACK' => 'A',
'LST_ALLERGENE' => '1:Gluten;3:Œufs;7:Lait',
'LST_ADDITIF' => 'E301:Ascorbate de sodium',
]);
}
public function filetCanardSudOuest(): self
{
return $this->state([
'NO_ART' => 48102,
'DENOM_LEG' => 'Magret de canard à rôtir du Sud-Ouest IGP',
'DESCRIPTIF' => 'Magret de canard du Sud-Ouest Le Gaulois',
'ASTUCES' => 'Quadrillez la peau en surface avant cuisson sans entamer la chair.',
'CONSEIL_PREPA' => 'Cuire côté peau 8 minutes à feu moyen, vider l\'excédent de graisse, puis cuire côté chair 5 minutes.',
'ARG_VENTE' => 'Canard fermier élevé, gavé et préparé dans le Sud-Ouest (IGP Canard à foie gras du Sud-Ouest).',
'ALLEGATIONS' => 'IGP Sud-Ouest, 100% canard français, sans additif',
'LST_ING' => 'Magret de canard avec peau (100% canard du Sud-Ouest).',
'NB_PORTION' => '2',
'MARQUE' => 1,
'FAMILLE_VTE' => 319,
'PDS_NET_UVC' => 350.0,
'PDS_BRUT_UVC' => 370.0,
'NUTRISCORE_ON_PACK' => 'A',
'LST_ALLERGENE' => null,
'LST_ADDITIF' => null,
]);
}
public function aiguillettesPouletThym(): self
{
return $this->state([
'NO_ART' => 52340,
'DENOM_LEG' => 'Aiguillettes de poulet marinées aux herbes de Provence et au citron',
'DESCRIPTIF' => 'Aiguillettes de poulet mariné thym & citron Maître CoQ',
'ASTUCES' => 'Parfaites pour des brochettes estivales ou des sautés au wok.',
'CONSEIL_PREPA' => 'A la poêle 6 minutes à feu vif en remuant régulièrement.',
'ARG_VENTE' => 'Une marinade fraîche et savoureuse sur des découpes tendres de volaille française.',
'ALLEGATIONS' => 'Volaille française, marinade sans huile de palme, arômes 100% naturels',
'LST_ING' => 'Aiguillettes de poulet (88%), marinade : 12% (eau, huile de colza, jus de citron concentré : 2%, '
. 'sel, thym : 0.8%, romarin, origan, ail déshydraté, arômes naturels, épaississant : gomme guar [E412]).',
'NB_PORTION' => '2',
'MARQUE' => 2,
'FAMILLE_VTE' => 94,
'PDS_NET_UVC' => 240.0,
'PDS_BRUT_UVC' => 260.0,
'NUTRISCORE_ON_PACK' => 'A',
'LST_ALLERGENE' => null,
'LST_ADDITIF' => 'E412:Gomme guar',
]);
}
public function gratinDauphinois(): self
{
return $this->state([
'NO_ART' => 63450,
'DENOM_LEG' => 'Gratin dauphinois traditionnel aux pommes de terre fraîches, crème et emmental',
'DESCRIPTIF' => 'Gratin Dauphinois à la crème fraîche Marie',
'ASTUCES' => 'Laissez gratiner jusqu\'à obtention d\'une belle croûte dorée.',
'CONSEIL_PREPA' => 'Au four préchauffé à 190°C pendant 20 minutes.',
'ARG_VENTE' => 'Pommes de terre d\'origine France, crème fraîche normande et cuisson lente au four.',
'ALLEGATIONS' => 'Pommes de terre françaises, crème fraîche d\'Isigny, sans conservateur',
'LST_ING' => 'Pommes de terre fraîches : 55%, CRÈME fraîche pasteurisée : 22%, LAIT demi-écrémé, '
. 'EMMENTAL français râpé : 6%, BEURRE, ail, sel, poivre noir, muscade. Traces éventuelles de gluten, œuf, céleri.',
'NB_PORTION' => '2',
'MARQUE' => 4,
'FAMILLE_VTE' => 120,
'PDS_NET_UVC' => 400.0,
'PDS_BRUT_UVC' => 430.0,
'NUTRISCORE_ON_PACK' => 'C',
'LST_ALLERGENE' => '7:Lait;1:Gluten;3:Œufs;9:Céleri',
'LST_ADDITIF' => null,
]);
}
}

View file

@ -60,7 +60,6 @@ use Database\ArcadiaReplicate\Views\Refp\IncoSocRefIncoView;
use Database\ArcadiaReplicate\Views\Refp\SitProdIncoView;
use Database\ArcadiaReplicate\Views\Refp\SocDlcIncoView;
use Database\ArcadiaReplicate\Views\Refp\VisuelExportGenfiView;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Schema;
final class Migrator
@ -125,11 +124,8 @@ final class Migrator
VisuelExportGenfiView::class,
];
private string $connection;
public function __construct(?string $connection = null)
public function __construct(private readonly string $connection)
{
$this->connection = $connection ?? Config::string('database.arcadia_meta_model');
}
public function up(): void
@ -150,12 +146,12 @@ final class Migrator
}
}
public static function runUp(?string $connection = null): void
public static function runUp(string $connection): void
{
(new self($connection))->up();
}
public static function runDown(?string $connection = null): void
public static function runDown(string $connection): void
{
(new self($connection))->down();
}

View file

@ -45,6 +45,8 @@ final class IncoTable implements TableOrView
$table->date('DAT_CRE')->nullable()->comment('Oracle: DATE(0, 0)');
$table->date('DAT_MAJ')->nullable()->comment('Oracle: DATE(0, 0)');
$table->bigInteger('NO_ART')->primary()->comment('Oracle: NUMBER(0, 0) [PK]');
$table->integer('MARQUE')->nullable()->comment('Oracle: NUMBER(5, 0) [FK -> MARQUE.COD_MARQ]');
$table->integer('FAMILLE_VTE')->nullable()->comment('Oracle: NUMBER(5, 0) [FK -> FAM_VENTE.COD_FAMVTE]');
$table->integer('UVERSION')->nullable()->comment('Oracle: NUMBER(5, 0)');
$table->text('MENTION_COMPL')->nullable()->comment('Oracle: VARCHAR2(0, 0)');
$table->smallInteger('EXPLOITANT')->nullable()->comment('Oracle: NUMBER(4, 0)');

View file

@ -30,7 +30,7 @@ final class BrandFactory extends Factory
return [
'id' => Uuid::uuid7()->toString(),
'name' => $name,
'arcadia_id' => fake()->unique()->numberBetween(1, 9999),
'arcadia_id' => fake()->unique()->numberBetween(1, 999),
'uwil_public_id' => $code->value,
];
}

View file

@ -4,7 +4,7 @@ declare(strict_types=1);
use Database\ArcadiaReplicate\Migrator;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Config;
use Infra\Config\ArcadiaStorageConfig;
return new class () extends Migration
{
@ -12,7 +12,7 @@ return new class () extends Migration
public function __construct()
{
$connection = Config::string('database.arcadia_meta_model');
$connection = resolve(ArcadiaStorageConfig::class)->databaseConnection;
$this->migrator = new Migrator($connection);
}

View file

@ -4,34 +4,37 @@ declare(strict_types=1);
namespace Database\Seeders;
use Application\Security\Config\HmacAuthConfig;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Str;
use Infra\Database\Models\ApiClient;
final class ApiClientSeeder extends Seeder
{
public function run(): void
public function run(?HmacAuthConfig $hmacAuthConfig = null): void
{
/** @var array{id: string, name: string, identifier: string, secret: string} $devClient */
$devClient = Config::array('auth.hmac.dev_client');
$now = now();
$hmacAuthConfig ??= resolve(HmacAuthConfig::class);
$devClient = $hmacAuthConfig->devClient;
if ($devClient === null) {
return;
}
$now = now();
ApiClient::query()->updateOrCreate(
['identifier' => $devClient['identifier']],
['identifier' => $devClient->identifier->value],
[
'id' => $devClient['id'],
'name' => $devClient['name'],
'slug' => Str::slug($devClient['name']),
'secret' => $devClient['secret'],
'id' => $devClient->id->value,
'name' => $devClient->name->value,
'slug' => Str::slug($devClient->name->value),
'secret' => $devClient->secret->value,
'is_active' => true,
'updated_at' => $now,
]
);
$this->command?->info('API client seeded successfully.');
$this->command?->info('Client ID: ' . $devClient['id']);
$this->command?->info('Client Identifier: ' . $devClient['identifier']);
$this->command?->info('Client Secret: ' . $devClient['secret']);
$this->command?->info('Client ID: ' . $devClient->id->value);
$this->command?->info('Client Identifier: ' . $devClient->identifier->value);
$this->command?->info('Client Secret: ' . $devClient->secret->value);
}
}

View file

@ -14,19 +14,7 @@ use Database\ArcadiaReplicate\Factories\Refp\IncoFactory;
use Database\ArcadiaReplicate\Factories\Refp\MarqueFactory;
use Database\ArcadiaReplicate\Factories\Refp\RuPersonneSirhFactory;
use Database\ArcadiaReplicate\Factories\Refp\ServiceConsoIncoFactory;
use Database\ArcadiaReplicate\Tables\Metap\MetaUtilTable;
use Database\ArcadiaReplicate\Tables\Refp\AdditifTable;
use Database\ArcadiaReplicate\Tables\Refp\FamVenteTable;
use Database\ArcadiaReplicate\Tables\Refp\IncoAllegationsTable;
use Database\ArcadiaReplicate\Tables\Refp\IncoAllergeneTable;
use Database\ArcadiaReplicate\Tables\Refp\IncoCompoTable;
use Database\ArcadiaReplicate\Tables\Refp\IncoTable;
use Database\ArcadiaReplicate\Tables\Refp\MarqueTable;
use Database\ArcadiaReplicate\Tables\Refp\RuPersonneSirhTable;
use Database\ArcadiaReplicate\Tables\Refp\ServiceConsoIncoTable;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
final class ArcadiaReplicateSeeder extends Seeder
{
@ -35,109 +23,315 @@ final class ArcadiaReplicateSeeder extends Seeder
*/
public function run(): void
{
$connection = Config::string('database.arcadia_meta_model');
$this->seedMetaUtil($connection);
$this->seedSirh($connection);
$this->seedMarques($connection);
$this->seedFamVente($connection);
$this->seedAdditifs($connection);
$this->seedAllergenesAndAllegations($connection);
$this->seedServicesConso($connection);
$this->seedIncoAndCompo($connection);
$this->seedMetaUtil();
$this->seedSirh();
$this->seedMarques();
$this->seedFamVente();
$this->seedAdditifs();
$this->seedAllergenesAndAllegations();
$this->seedServicesConso();
$this->seedIncoAndCompo();
}
private function seedMetaUtil(string $connection): void
private function seedMetaUtil(): void
{
$users = [
['COD_UTIL' => 'RA0706430', 'LIB_UTIL' => 'Responsable Qualité', 'EMAIL' => 'qualite@ldc.fr', 'GROUPE' => 65],
['COD_UTIL' => 'RA0706430', 'LIB_UTIL' => 'Responsable Qualité Groupe', 'EMAIL' => 'qualite@ldc.fr', 'GROUPE' => 65],
['COD_UTIL' => 'BM6501226', 'LIB_UTIL' => 'Chef de Produit Marketing', 'EMAIL' => 'marketing@ldc.fr', 'GROUPE' => 2],
['COD_UTIL' => 'SB6501847', 'LIB_UTIL' => 'Responsable Commercial', 'EMAIL' => 'commercial@ldc.fr', 'GROUPE' => 1],
['COD_UTIL' => 'ME0101979', 'LIB_UTIL' => 'Administrateur SI', 'EMAIL' => 'admin.si@ldc.fr', 'GROUPE' => 0],
['COD_UTIL' => 'SG6501248', 'LIB_UTIL' => 'Chargé R&D Nutrition', 'EMAIL' => 'rd.nutrition@ldc.fr', 'GROUPE' => 1],
['COD_UTIL' => 'SB6501847', 'LIB_UTIL' => 'Responsable Commercial GMS', 'EMAIL' => 'commercial@ldc.fr', 'GROUPE' => 1],
['COD_UTIL' => 'ME0101979', 'LIB_UTIL' => 'Administrateur SI Référentiels', 'EMAIL' => 'admin.si@ldc.fr', 'GROUPE' => 0],
['COD_UTIL' => 'SG6501248', 'LIB_UTIL' => 'Ingénieur R&D Nutrition', 'EMAIL' => 'rd.nutrition@ldc.fr', 'GROUPE' => 1],
['COD_UTIL' => 'JL7201944', 'LIB_UTIL' => 'Auditeur Réglementaire INCO', 'EMAIL' => 'audit.reg@ldc.fr', 'GROUPE' => 65],
];
foreach ($users as $user) {
if (! DB::connection($connection)->table(MetaUtilTable::name())->where('COD_UTIL', $user['COD_UTIL'])->exists()) {
MetaUtilFactory::new($connection)->create($user);
if (! MetaUtilFactory::query()->where('COD_UTIL', $user['COD_UTIL'])->exists()) {
MetaUtilFactory::new()->create($user);
}
}
}
private function seedSirh(string $connection): void
private function seedSirh(): void
{
$employees = [
['MATRICULE_FIC' => '4300710', 'SITE_FIC' => 'AVIGNO', 'ETAB_FIC' => 'ET29A', 'STATUT_FIC' => 'OUV', 'SERVICE_FIC' => '25'],
['5000920', 'SNVSER', 'ET11G', 'OUV', '13'],
['3900757', 'EPC', 'ET15', 'AMT', '16'],
['109873', 'LDCVOL', 'ET50', 'CAD', '25'],
['4911791', 'SNVVOL', 'ET11E', 'OUV', '11'],
// Salarié historique de référence pour Bruno & tests API
[
'MATRICULE_FIC' => '01155902',
'COD_PERSONNE' => '01155902',
'NOM_FIC' => 'DOE',
'NOM_PERSONNE' => 'DOE',
'PRENOM_FIC' => 'John',
'PRENOM_PERSONNE' => 'John',
'SITE_FIC' => 'LDCSER',
'ETAB_FIC' => '01',
'ETABLISSEMENT' => '01',
'STATUT_FIC' => 'CAD',
'SERVICE_FIC' => '097',
'DATE_DEB_FIC' => '2024-01-15',
'DATE_ENTREE' => '2024-01-15',
'DATE_FIN_FIC' => null,
'DF_CARRIERE' => null,
],
[
'MATRICULE_FIC' => '1234567',
'COD_PERSONNE' => '1234567',
'NOM_FIC' => 'MARTIN',
'NOM_PERSONNE' => 'MARTIN',
'PRENOM_FIC' => 'Alice',
'PRENOM_PERSONNE' => 'Alice',
'SITE_FIC' => 'LDCSER',
'ETAB_FIC' => 'LY',
'ETABLISSEMENT' => 'LY',
'STATUT_FIC' => 'CAD',
'SERVICE_FIC' => '101',
'DATE_DEB_FIC' => '2024-01-08',
'DATE_ENTREE' => '2024-01-08',
'DATE_FIN_FIC' => null,
'DF_CARRIERE' => null,
],
[
'MATRICULE_FIC' => '2345678',
'COD_PERSONNE' => '2345678',
'NOM_FIC' => 'DUPONT',
'NOM_PERSONNE' => 'DUPONT',
'PRENOM_FIC' => 'Louis',
'PRENOM_PERSONNE' => 'Louis',
'SITE_FIC' => 'SLELA',
'ETAB_FIC' => 'PA',
'ETABLISSEMENT' => 'PA',
'STATUT_FIC' => 'AMT',
'SERVICE_FIC' => '097',
'DATE_DEB_FIC' => '2023-05-15',
'DATE_ENTREE' => '2023-05-15',
'DATE_FIN_FIC' => null,
'DF_CARRIERE' => '2026-12-31',
],
[
'MATRICULE_FIC' => '3456789',
'COD_PERSONNE' => '3456789',
'NOM_FIC' => 'BERNARD',
'NOM_PERSONNE' => 'BERNARD',
'PRENOM_FIC' => 'Nora',
'PRENOM_PERSONNE' => 'Nora',
'SITE_FIC' => 'DDE',
'ETAB_FIC' => 'BO',
'ETABLISSEMENT' => 'BO',
'STATUT_FIC' => 'OUV',
'SERVICE_FIC' => '205',
'DATE_DEB_FIC' => '2022-09-01',
'DATE_ENTREE' => '2022-09-01',
'DATE_FIN_FIC' => null,
'DF_CARRIERE' => null,
],
[
'MATRICULE_FIC' => '4300710',
'COD_PERSONNE' => '4300710',
'NOM_FIC' => 'GARCIA',
'NOM_PERSONNE' => 'GARCIA',
'PRENOM_FIC' => 'Manuel',
'PRENOM_PERSONNE' => 'Manuel',
'SITE_FIC' => 'AVIGNO',
'ETAB_FIC' => 'ET29A',
'ETABLISSEMENT' => 'ET29A',
'STATUT_FIC' => 'OUV',
'SERVICE_FIC' => '25',
'DATE_DEB_FIC' => '2020-03-01',
'DATE_ENTREE' => '2020-03-01',
'DATE_FIN_FIC' => null,
'DF_CARRIERE' => null,
],
[
'MATRICULE_FIC' => '5000920',
'COD_PERSONNE' => '5000920',
'NOM_FIC' => 'LEFEBVRE',
'NOM_PERSONNE' => 'LEFEBVRE',
'PRENOM_FIC' => 'Claire',
'PRENOM_PERSONNE' => 'Claire',
'SITE_FIC' => 'SNVSER',
'ETAB_FIC' => 'ET11G',
'ETABLISSEMENT' => 'ET11G',
'STATUT_FIC' => 'AMT',
'SERVICE_FIC' => '13',
'DATE_DEB_FIC' => '2019-11-15',
'DATE_ENTREE' => '2019-11-15',
'DATE_FIN_FIC' => null,
'DF_CARRIERE' => null,
],
[
'MATRICULE_FIC' => '3900757',
'COD_PERSONNE' => '3900757',
'NOM_FIC' => 'MOREAU',
'NOM_PERSONNE' => 'MOREAU',
'PRENOM_FIC' => 'Julien',
'PRENOM_PERSONNE' => 'Julien',
'SITE_FIC' => 'EPC',
'ETAB_FIC' => 'ET15',
'ETABLISSEMENT' => 'ET15',
'STATUT_FIC' => 'AMT',
'SERVICE_FIC' => '16',
'DATE_DEB_FIC' => '2021-06-01',
'DATE_ENTREE' => '2021-06-01',
'DATE_FIN_FIC' => null,
'DF_CARRIERE' => null,
],
[
'MATRICULE_FIC' => '0109873',
'COD_PERSONNE' => '0109873',
'NOM_FIC' => 'PETIT',
'NOM_PERSONNE' => 'PETIT',
'PRENOM_FIC' => 'Thomas',
'PRENOM_PERSONNE' => 'Thomas',
'SITE_FIC' => 'LDCVOL',
'ETAB_FIC' => 'ET50',
'ETABLISSEMENT' => 'ET50',
'STATUT_FIC' => 'CAD',
'SERVICE_FIC' => '25',
'DATE_DEB_FIC' => '2018-04-10',
'DATE_ENTREE' => '2018-04-10',
'DATE_FIN_FIC' => null,
'DF_CARRIERE' => null,
],
[
'MATRICULE_FIC' => '4911791',
'COD_PERSONNE' => '4911791',
'NOM_FIC' => 'ROUX',
'NOM_PERSONNE' => 'ROUX',
'PRENOM_FIC' => 'Sophie',
'PRENOM_PERSONNE' => 'Sophie',
'SITE_FIC' => 'SNVVOL',
'ETAB_FIC' => 'ET11E',
'ETABLISSEMENT' => 'ET11E',
'STATUT_FIC' => 'OUV',
'SERVICE_FIC' => '11',
'DATE_DEB_FIC' => '2022-01-10',
'DATE_ENTREE' => '2022-01-10',
'DATE_FIN_FIC' => null,
'DF_CARRIERE' => null,
],
[
'MATRICULE_FIC' => '0812345',
'COD_PERSONNE' => '0812345',
'NOM_FIC' => 'DAVID',
'NOM_PERSONNE' => 'DAVID',
'PRENOM_FIC' => 'Camille',
'PRENOM_PERSONNE' => 'Camille',
'SITE_FIC' => 'LDCSER',
'ETAB_FIC' => '01',
'ETABLISSEMENT' => '01',
'STATUT_FIC' => 'CAD',
'SERVICE_FIC' => '097',
'DATE_DEB_FIC' => '2015-09-01',
'DATE_ENTREE' => '2015-09-01',
'DATE_FIN_FIC' => '2025-06-30',
'DF_CARRIERE' => '2025-06-30',
],
[
'MATRICULE_FIC' => '0923456',
'COD_PERSONNE' => '0923456',
'NOM_FIC' => 'BERTRAND',
'NOM_PERSONNE' => 'BERTRAND',
'PRENOM_FIC' => 'Hugo',
'PRENOM_PERSONNE' => 'Hugo',
'SITE_FIC' => 'SLELA',
'ETAB_FIC' => 'PA',
'ETABLISSEMENT' => 'PA',
'STATUT_FIC' => 'OUV',
'SERVICE_FIC' => '097',
'DATE_DEB_FIC' => '2023-10-01',
'DATE_ENTREE' => '2023-10-01',
'DATE_FIN_FIC' => null,
'DF_CARRIERE' => null,
],
[
'MATRICULE_FIC' => '0734567',
'COD_PERSONNE' => '0734567',
'NOM_FIC' => 'FOURNIER',
'NOM_PERSONNE' => 'FOURNIER',
'PRENOM_FIC' => 'Émilie',
'PRENOM_PERSONNE' => 'Émilie',
'SITE_FIC' => 'AVIGNO',
'ETAB_FIC' => 'ET29A',
'ETABLISSEMENT' => 'ET29A',
'STATUT_FIC' => 'AMT',
'SERVICE_FIC' => '25',
'DATE_DEB_FIC' => '2021-02-15',
'DATE_ENTREE' => '2021-02-15',
'DATE_FIN_FIC' => null,
'DF_CARRIERE' => null,
],
];
foreach ($employees as $emp) {
$mat = is_array($emp) && isset($emp['MATRICULE_FIC']) ? $emp['MATRICULE_FIC'] : $emp[0];
if (! DB::connection($connection)->table(RuPersonneSirhTable::name())->where('MATRICULE_FIC', $mat)->exists()) {
if (isset($emp['MATRICULE_FIC'])) {
RuPersonneSirhFactory::new($connection)->create($emp);
} else {
RuPersonneSirhFactory::new($connection)->create([
'MATRICULE_FIC' => $emp[0],
'COD_PERSONNE' => $emp[0],
'SITE_FIC' => $emp[1],
'ETAB_FIC' => $emp[2],
'ETABLISSEMENT' => $emp[2],
'STATUT_FIC' => $emp[3],
'SERVICE_FIC' => $emp[4],
]);
}
if (! RuPersonneSirhFactory::query()->where('MATRICULE_FIC', $emp['MATRICULE_FIC'])->exists()) {
RuPersonneSirhFactory::new()->create($emp);
}
}
}
private function seedMarques(string $connection): void
private function seedMarques(): void
{
$marques = [
['COD_MARQ' => 246, 'LIB_MARQ' => 'LE GAULOIS', 'COMMENTAIRE' => 'Marque Le Gaulois (Volailles & Panés)'],
['COD_MARQ' => 466, 'LIB_MARQ' => 'LOUE', 'COMMENTAIRE' => 'Fermiers de Loué Label Rouge'],
['COD_MARQ' => 565, 'LIB_MARQ' => 'MARIE', 'COMMENTAIRE' => 'Plats cuisinés & surgelés Marie'],
['COD_MARQ' => 71, 'LIB_MARQ' => 'ID HALAL', 'COMMENTAIRE' => 'Gamme certifiée Halal'],
['COD_MARQ' => 793, 'LIB_MARQ' => 'POPROSTU', 'COMMENTAIRE' => 'Marque MDD pour la Pologne'],
['COD_MARQ' => 631, 'LIB_MARQ' => 'LA MAISON DE MAURICE', 'COMMENTAIRE' => 'Marque distributeur Export'],
['COD_MARQ' => 179, 'LIB_MARQ' => 'BX FOOD', 'COMMENTAIRE' => 'Marque BX Food'],
['COD_MARQ' => 725, 'LIB_MARQ' => 'ALPEKER', 'COMMENTAIRE' => 'Marque Export Italie'],
['COD_MARQ' => 740, 'LIB_MARQ' => 'AQUILA', 'COMMENTAIRE' => 'Marque Export Hongrie'],
['COD_MARQ' => 1, 'LIB_MARQ' => 'LE GAULOIS', 'COMMENTAIRE' => 'Marque Le Gaulois (Volailles & Panés)'],
['COD_MARQ' => 2, 'LIB_MARQ' => 'MAITRE COQ', 'COMMENTAIRE' => 'Marque Maître CoQ (Volailles & Élaborés)'],
['COD_MARQ' => 3, 'LIB_MARQ' => 'LOUE', 'COMMENTAIRE' => 'Fermiers de Loué Label Rouge'],
['COD_MARQ' => 4, 'LIB_MARQ' => 'MARIE', 'COMMENTAIRE' => 'Plats cuisinés frais & surgelés Marie'],
['COD_MARQ' => 5, 'LIB_MARQ' => "TRADITION D'ASIE", 'COMMENTAIRE' => 'Spécialités traiteur asiatiques'],
['COD_MARQ' => 6, 'LIB_MARQ' => 'REGHALAL', 'COMMENTAIRE' => 'Gamme certifiée Halal'],
['COD_MARQ' => 7, 'LIB_MARQ' => 'POPROSTU', 'COMMENTAIRE' => 'Marque MDD pour la Pologne'],
['COD_MARQ' => 8, 'LIB_MARQ' => 'LA MAISON DE MAURICE', 'COMMENTAIRE' => 'Marque distributeur Export'],
['COD_MARQ' => 9, 'LIB_MARQ' => 'ALPEKER', 'COMMENTAIRE' => 'Marque Export Italie'],
['COD_MARQ' => 10, 'LIB_MARQ' => 'AQUILA', 'COMMENTAIRE' => 'Marque Export Hongrie'],
['COD_MARQ' => 11, 'LIB_MARQ' => 'POUCE AUCHAN', 'COMMENTAIRE' => 'Marque premier prix Auchan'],
['COD_MARQ' => 12, 'LIB_MARQ' => 'CARREFOUR SIMPL', 'COMMENTAIRE' => 'Marque premier prix Carrefour'],
['COD_MARQ' => 246, 'LIB_MARQ' => 'LE GAULOIS (LEGACY)', 'COMMENTAIRE' => 'Code historique 246 Le Gaulois'],
['COD_MARQ' => 466, 'LIB_MARQ' => 'LOUE (LEGACY)', 'COMMENTAIRE' => 'Code historique 466 Loué'],
['COD_MARQ' => 565, 'LIB_MARQ' => 'MARIE (LEGACY)', 'COMMENTAIRE' => 'Code historique 565 Marie'],
];
foreach ($marques as $marque) {
if (! DB::connection($connection)->table(MarqueTable::name())->where('COD_MARQ', $marque['COD_MARQ'])->exists()) {
MarqueFactory::new($connection)->create($marque);
if (! MarqueFactory::query()->where('COD_MARQ', $marque['COD_MARQ'])->exists()) {
MarqueFactory::new()->create($marque);
}
}
}
private function seedFamVente(string $connection): void
private function seedFamVente(): void
{
$familles = [
['COD_FAMVTE' => 406, 'LIB_FAMVTE' => 'FOURNITURES EXPEDITION'],
['COD_FAMVTE' => 31, 'LIB_FAMVTE' => 'PRODUITS CUITS (TVA 20%)'],
['COD_FAMVTE' => 31, 'LIB_FAMVTE' => 'PRODUITS CUITS & PANES'],
['COD_FAMVTE' => 94, 'LIB_FAMVTE' => 'DCPE POULET NOIR'],
['COD_FAMVTE' => 306, 'LIB_FAMVTE' => 'OIE LOUE'],
['COD_FAMVTE' => 306, 'LIB_FAMVTE' => 'OIE & CANARD LOUE'],
['COD_FAMVTE' => 319, 'LIB_FAMVTE' => 'DCPE CANARD GRAS ELABORE'],
['COD_FAMVTE' => 120, 'LIB_FAMVTE' => 'PLATS CUISINES FRAIS'],
['COD_FAMVTE' => 135, 'LIB_FAMVTE' => 'TRAITEUR ASIATIQUE'],
['COD_FAMVTE' => 150, 'LIB_FAMVTE' => 'CHARCUTERIE DE VOLAILLE'],
];
foreach ($familles as $fam) {
if (! DB::connection($connection)->table(FamVenteTable::name())->where('COD_FAMVTE', $fam['COD_FAMVTE'])->exists()) {
FamVenteFactory::new($connection)->create($fam);
if (! FamVenteFactory::query()->where('COD_FAMVTE', $fam['COD_FAMVTE'])->exists()) {
FamVenteFactory::new()->create($fam);
}
}
}
private function seedAdditifs(string $connection): void
private function seedAdditifs(): void
{
$additifs = [
['COD_EUROPEEN' => 'E250', 'MOLECULE' => 'Nitrite de sodium', 'FONCTION' => 'Conservateur', 'RISQUE' => 2],
['COD_EUROPEEN' => 'E300', 'MOLECULE' => 'Acide ascorbique', 'FONCTION' => 'Antioxydant', 'RISQUE' => 0],
['COD_EUROPEEN' => 'E301', 'MOLECULE' => 'Ascorbate de sodium', 'FONCTION' => 'Antioxydant', 'RISQUE' => 0],
['COD_EUROPEEN' => 'E316', 'MOLECULE' => 'Érythorbate de sodium', 'FONCTION' => 'Antioxydant', 'RISQUE' => 1],
['COD_EUROPEEN' => 'E322', 'MOLECULE' => 'Lécithines', 'FONCTION' => 'Émulsifiant', 'RISQUE' => 0],
['COD_EUROPEEN' => 'E330', 'MOLECULE' => 'Acide citrique', 'FONCTION' => 'Acidifiant', 'RISQUE' => 0],
['COD_EUROPEEN' => 'E331', 'MOLECULE' => 'Citrates de sodium', 'FONCTION' => 'Régulateur d\'acidité', 'RISQUE' => 0],
['COD_EUROPEEN' => 'E392', 'MOLECULE' => 'Extrait de romarin', 'FONCTION' => 'Antioxydant', 'RISQUE' => 0],
['COD_EUROPEEN' => 'E407', 'MOLECULE' => 'Carraghénanes', 'FONCTION' => 'Gélifiant', 'RISQUE' => 1],
['COD_EUROPEEN' => 'E412', 'MOLECULE' => 'Gomme guar', 'FONCTION' => 'Épaississant', 'RISQUE' => 0],
['COD_EUROPEEN' => 'E415', 'MOLECULE' => 'Gomme xanthane', 'FONCTION' => 'Épaississant', 'RISQUE' => 0],
['COD_EUROPEEN' => 'E450', 'MOLECULE' => 'Diphosphates', 'FONCTION' => 'Stabilisant', 'RISQUE' => 1],
['COD_EUROPEEN' => 'E451', 'MOLECULE' => 'Triphosphates', 'FONCTION' => 'Stabilisant', 'RISQUE' => 1],
['COD_EUROPEEN' => 'E452', 'MOLECULE' => 'Polyphosphates', 'FONCTION' => 'Sels de fonte', 'RISQUE' => 1],
['COD_EUROPEEN' => 'E469', 'MOLECULE' => 'Carboxyméthylcellulose enzymatique', 'FONCTION' => 'Épaississant', 'RISQUE' => 1],
['COD_EUROPEEN' => 'E470a', 'MOLECULE' => 'Sels d\'acides gras', 'FONCTION' => 'Émulsifiant', 'RISQUE' => 1],
['COD_EUROPEEN' => 'E471', 'MOLECULE' => 'Mono et diglycérides d\'acides gras', 'FONCTION' => 'Émulsifiant', 'RISQUE' => 1],
@ -146,50 +340,58 @@ final class ArcadiaReplicateSeeder extends Seeder
];
foreach ($additifs as $additif) {
if (! DB::connection($connection)->table(AdditifTable::name())->where('COD_EUROPEEN', $additif['COD_EUROPEEN'])->exists()) {
AdditifFactory::new($connection)->create($additif);
if (! AdditifFactory::query()->where('COD_EUROPEEN', $additif['COD_EUROPEEN'])->exists()) {
AdditifFactory::new()->create($additif);
}
}
}
private function seedAllergenesAndAllegations(string $connection): void
private function seedAllergenesAndAllegations(): void
{
$allergenes = [
['ID' => 1, 'LIB' => 'Gluten'],
['ID' => 2, 'LIB' => 'Crustacés'],
['ID' => 3, 'LIB' => 'Œufs'],
['ID' => 4, 'LIB' => 'Poissons'],
['ID' => 5, 'LIB' => 'Arachides'],
['ID' => 6, 'LIB' => 'Soja'],
['ID' => 7, 'LIB' => 'Lait'],
['ID' => 1, 'LIB' => 'Céréales contenant du gluten'],
['ID' => 2, 'LIB' => 'Crustacés et produits à base de crustacés'],
['ID' => 3, 'LIB' => 'Œufs et produits à base d\'œufs'],
['ID' => 4, 'LIB' => 'Poissons et produits à base de poissons'],
['ID' => 5, 'LIB' => 'Arachides et produits à base d\'arachides'],
['ID' => 6, 'LIB' => 'Soja et produits à base de soja'],
['ID' => 7, 'LIB' => 'Lait et produits à base de lait (y compris le lactose)'],
['ID' => 8, 'LIB' => 'Fruits à coque'],
['ID' => 9, 'LIB' => 'Céleri'],
['ID' => 10, 'LIB' => 'Moutarde'],
['ID' => 11, 'LIB' => 'Graines de sésame'],
['ID' => 9, 'LIB' => 'Céleri et produits à base de céleri'],
['ID' => 10, 'LIB' => 'Moutarde et produits à base de moutarde'],
['ID' => 11, 'LIB' => 'Graines de sésame et produits à base de graines de sésame'],
['ID' => 12, 'LIB' => 'Anhydride sulfureux et sulfites (>10mg/kg)'],
['ID' => 13, 'LIB' => 'Lupin et produits à base de lupin'],
['ID' => 14, 'LIB' => 'Mollusques et produits à base de mollusques'],
];
foreach ($allergenes as $allergene) {
if (! DB::connection($connection)->table(IncoAllergeneTable::name())->where('ID', $allergene['ID'])->exists()) {
IncoAllergeneFactory::new($connection)->create($allergene);
if (! IncoAllergeneFactory::query()->where('ID', $allergene['ID'])->exists()) {
IncoAllergeneFactory::new()->create($allergene);
}
}
$allegations = [
['CODE' => 1, 'LIBELLE' => 'Sans conservateur'],
['CODE' => 2, 'LIBELLE' => 'Sans huile de palme'],
['CODE' => 3, 'LIBELLE' => 'Volaille 100% française'],
['CODE' => 4, 'LIBELLE' => 'Élevé en liberté 84 jours'],
['CODE' => 5, 'LIBELLE' => 'Sans arôme artificiel'],
['CODE' => 1, 'LIBELLE' => 'Sans conservateur'],
['CODE' => 2, 'LIBELLE' => 'Sans huile de palme'],
['CODE' => 3, 'LIBELLE' => 'Volaille 100% française'],
['CODE' => 4, 'LIBELLE' => 'Élevé en liberté 84 jours'],
['CODE' => 5, 'LIBELLE' => 'Sans arôme artificiel'],
['CODE' => 6, 'LIBELLE' => 'Certifié Halal'],
['CODE' => 7, 'LIBELLE' => 'Label Rouge'],
['CODE' => 8, 'LIBELLE' => 'Nourri sans OGM (<0.9%)'],
['CODE' => 9, 'LIBELLE' => 'Riche en protéines'],
['CODE' => 10, 'LIBELLE' => 'Viande bovine française (VBF)'],
];
foreach ($allegations as $allegation) {
if (! DB::connection($connection)->table(IncoAllegationsTable::name())->where('CODE', $allegation['CODE'])->exists()) {
IncoAllegationsFactory::new($connection)->create($allegation);
if (! IncoAllegationsFactory::query()->where('CODE', $allegation['CODE'])->exists()) {
IncoAllegationsFactory::new()->create($allegation);
}
}
}
private function seedServicesConso(string $connection): void
private function seedServicesConso(): void
{
$services = [
[
@ -200,7 +402,7 @@ final class ArcadiaReplicateSeeder extends Seeder
'VILLE' => 'Villeneuve d\'Ascq',
'TELEPHONE' => '03.59.30.59.30',
'MAIL' => 'service.conso@auchan.fr',
'MARQUE' => 210,
'MARQUE' => 11,
'LIB' => 'Service conso Pouce Auchan',
'SITE_INT' => 'www.auchan.fr',
],
@ -212,22 +414,10 @@ final class ArcadiaReplicateSeeder extends Seeder
'VILLE' => 'Massy',
'TELEPHONE' => '06.69.39.70.00',
'MAIL' => 'service.conso@carrefour.fr',
'MARQUE' => 448,
'LIB' => 'Service conso Carrefour',
'MARQUE' => 12,
'LIB' => 'Service conso Carrefour Simpl',
'SITE_INT' => 'www.carrefour.fr',
],
[
'ID' => 30,
'NOM' => 'Service clients Intermarché',
'ADRESSE1' => '24 rue Auguste Chabrières',
'CP' => '75000',
'VILLE' => 'Paris',
'TELEPHONE' => '08.00.00.81.80',
'MAIL' => 'service.conso@intermarche.com',
'MARQUE' => 419,
'LIB' => 'Service conso Intermarché',
'SITE_INT' => 'www.intermarche.com',
],
[
'ID' => 54,
'NOM' => 'Service Consommateurs LDC',
@ -236,41 +426,59 @@ final class ArcadiaReplicateSeeder extends Seeder
'VILLE' => 'Sablé-sur-Sarthe',
'TELEPHONE' => '02.43.62.70.00',
'MAIL' => 'service.conso@ldc.fr',
'MARQUE' => 246,
'LIB' => 'Service conso Groupe LDC',
'MARQUE' => 1,
'LIB' => 'Service conso Groupe LDC (Le Gaulois, Marie, Loué, Maître CoQ)',
'SITE_INT' => 'www.ldc.fr',
],
];
foreach ($services as $service) {
if (! DB::connection($connection)->table(ServiceConsoIncoTable::name())->where('ID', $service['ID'])->exists()) {
ServiceConsoIncoFactory::new($connection)->create($service);
if (! ServiceConsoIncoFactory::query()->where('ID', $service['ID'])->exists()) {
ServiceConsoIncoFactory::new()->create($service);
}
}
}
private function seedIncoAndCompo(string $connection): void
private function seedIncoAndCompo(): void
{
// 1. Compositions nutritionnelles
if (! DB::connection($connection)->table(IncoCompoTable::name())->where('ID', 96504)->exists()) {
IncoCompoFactory::new($connection)->steaksDinde()->create();
}
$compos = [
96504 => fn () => IncoCompoFactory::new()->steaksDinde()->create(),
124503 => fn () => IncoCompoFactory::new()->pouletFermierNoir()->create(),
124504 => fn () => IncoCompoFactory::new()->pouletFermierLoue()->create(),
130101 => fn () => IncoCompoFactory::new()->cordonBleuDinde()->create(),
140205 => fn () => IncoCompoFactory::new()->lasagnesBolognaise()->create(),
150312 => fn () => IncoCompoFactory::new()->nemsPoulet()->create(),
160420 => fn () => IncoCompoFactory::new()->emincesPouletRoti()->create(),
170502 => fn () => IncoCompoFactory::new()->filetCanardSudOuest()->create(),
180640 => fn () => IncoCompoFactory::new()->aiguillettesPouletThym()->create(),
190750 => fn () => IncoCompoFactory::new()->gratinDauphinois()->create(),
];
if (! DB::connection($connection)->table(IncoCompoTable::name())->where('ID', 124503)->exists()) {
IncoCompoFactory::new($connection)->pouletFermierNoir()->create();
foreach ($compos as $compoId => $creator) {
if (! IncoCompoFactory::query()->where('ID', $compoId)->exists()) {
$creator();
}
}
// 2. Fiches INCO liées
if (! DB::connection($connection)->table(IncoTable::name())->where('NO_ART', 47789)->exists()) {
IncoFactory::new($connection)->nuggetsPoulet()->withCompo(96504)->create();
}
$articles = [
47789 => fn () => IncoFactory::new()->nuggetsPoulet()->withCompo(96504)->create(),
47996 => fn () => IncoFactory::new()->gesiersEtFoies()->withCompo(124503)->create(),
4 => fn () => IncoFactory::new()->pouletFermierLoue()->withCompo(124504)->create(),
51201 => fn () => IncoFactory::new()->cordonBleuDinde()->withCompo(130101)->create(),
62305 => fn () => IncoFactory::new()->lasagnesBolognaise()->withCompo(140205)->create(),
73412 => fn () => IncoFactory::new()->nemsPoulet()->withCompo(150312)->create(),
84520 => fn () => IncoFactory::new()->emincesPouletRoti()->withCompo(160420)->create(),
48102 => fn () => IncoFactory::new()->filetCanardSudOuest()->withCompo(170502)->create(),
52340 => fn () => IncoFactory::new()->aiguillettesPouletThym()->withCompo(180640)->create(),
63450 => fn () => IncoFactory::new()->gratinDauphinois()->withCompo(190750)->create(),
];
if (! DB::connection($connection)->table(IncoTable::name())->where('NO_ART', 47996)->exists()) {
IncoFactory::new($connection)->gesiersEtFoies()->withCompo(124503)->create();
}
if (! DB::connection($connection)->table(IncoTable::name())->where('NO_ART', 4)->exists()) {
IncoFactory::new($connection)->pouletFermierLoue()->create();
foreach ($articles as $artId => $creator) {
if (! IncoFactory::query()->where('NO_ART', $artId)->exists()) {
$creator();
}
}
}
}

View file

@ -17,12 +17,18 @@ final class BrandSeeder extends Seeder
{
/** @var list<array{code: int, libelle: string, uwil_public_id: string}> $brands */
$brands = [
['code' => 1, 'libelle' => 'Le Gaulois', 'uwil_public_id' => 'LGL01'],
['code' => 2, 'libelle' => 'Maître CoQ', 'uwil_public_id' => 'MCQ02'],
['code' => 3, 'libelle' => 'Loué', 'uwil_public_id' => 'LOU03'],
['code' => 4, 'libelle' => 'Marie', 'uwil_public_id' => 'MAR04'],
['code' => 5, 'libelle' => "Tradition d'Asie", 'uwil_public_id' => 'TDA05'],
['code' => 6, 'libelle' => 'Réghalal', 'uwil_public_id' => 'REG06'],
['code' => 1, 'libelle' => 'Le Gaulois', 'uwil_public_id' => 'LGL01'],
['code' => 2, 'libelle' => 'Maître CoQ', 'uwil_public_id' => 'MCQ02'],
['code' => 3, 'libelle' => 'Loué', 'uwil_public_id' => 'LOU03'],
['code' => 4, 'libelle' => 'Marie', 'uwil_public_id' => 'MAR04'],
['code' => 5, 'libelle' => "Tradition d'Asie", 'uwil_public_id' => 'TDA05'],
['code' => 6, 'libelle' => 'Réghalal', 'uwil_public_id' => 'REG06'],
['code' => 7, 'libelle' => 'Poprostu', 'uwil_public_id' => 'POP07'],
['code' => 8, 'libelle' => 'La Maison de Maurice', 'uwil_public_id' => 'MDM08'],
['code' => 9, 'libelle' => 'Alpeker', 'uwil_public_id' => 'ALP09'],
['code' => 10, 'libelle' => 'Aquila', 'uwil_public_id' => 'AQU10'],
['code' => 11, 'libelle' => 'Pouce Auchan', 'uwil_public_id' => 'POU12'],
['code' => 12, 'libelle' => 'Carrefour Simpl', 'uwil_public_id' => 'CAR13'],
];
foreach ($brands as $brandData) {

View file

@ -14,7 +14,6 @@ final class DatabaseSeeder extends Seeder
public function run(): void
{
$this->call([
EmployeeSeeder::class,
ApiClientSeeder::class,
BrandSeeder::class,
ArcadiaReplicateSeeder::class,

View file

@ -2,14 +2,14 @@
declare(strict_types=1);
use Illuminate\Support\Facades\Config;
use Application\Arcadia\Config\AppConfig;
use Illuminate\Support\Facades\Route;
// * Api Root URL
Route::get(
'/',
fn () => response()->json([
'message' => Config::string('app.name') . ' please choose a version',
'message' => resolve(AppConfig::class)->name->value . ' please choose a version',
'versions' => [
'v1' => route('api.v1.root'),
],

View file

@ -2,7 +2,7 @@
declare(strict_types=1);
use Illuminate\Support\Facades\Config;
use Application\Arcadia\Config\AppConfig;
use Illuminate\Support\Facades\Route;
use Presentation\Api\V1\Http\Controllers\Brands\BrandShowController;
use Presentation\Api\V1\Http\Controllers\Brands\BrandsIndexController;
@ -26,7 +26,7 @@ use Presentation\Api\V1\Http\Controllers\IncoSheets\IncoSheetsShowController;
// * ROOT
Route::get('/', fn () => response()->json([
'message' => Config::string('app.name') . ' v1',
'message' => resolve(AppConfig::class)->name->value . ' v1',
'spec' => route('api.v1.openapi'),
]))->name('root');

View file

@ -16,10 +16,16 @@ use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Infra\Config\ArcadiaStorageConfig;
use Shared\Time\Utc;
final readonly class LaravelSystemHealthChecker implements HealthChecker
{
public function __construct(
private ArcadiaStorageConfig $storageConfig,
) {
}
#[\Override]
public function check(): HealthCheckResult
{
@ -66,7 +72,7 @@ final readonly class LaravelSystemHealthChecker implements HealthChecker
private function checkArcadiaDatabase(): DatabaseCheckResult
{
$connection = Config::string('database.arcadia_meta_model', 'arcadia');
$connection = $this->storageConfig->databaseConnection;
try {
DB::connection($connection)->select('SELECT 1');

View file

@ -4,35 +4,30 @@ declare(strict_types=1);
namespace Tests\Integration\Database\Seeders;
use Database\ArcadiaReplicate\Tables\Metap\MetaUtilTable;
use Database\ArcadiaReplicate\Tables\Refp\IncoCompoTable;
use Database\ArcadiaReplicate\Tables\Refp\IncoTable;
use Database\ArcadiaReplicate\Tables\Refp\MarqueTable;
use Database\ArcadiaReplicate\Tables\Refp\RuPersonneSirhTable;
use Database\ArcadiaReplicate\Factories\Metap\MetaUtilFactory;
use Database\ArcadiaReplicate\Factories\Refp\IncoCompoFactory;
use Database\ArcadiaReplicate\Factories\Refp\IncoFactory;
use Database\ArcadiaReplicate\Factories\Refp\MarqueFactory;
use Database\ArcadiaReplicate\Factories\Refp\RuPersonneSirhFactory;
use Database\Seeders\ArcadiaReplicateSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
covers(ArcadiaReplicateSeeder::class);
uses(TestCase::class, RefreshDatabase::class);
describe('ArcadiaReplicateSeeder Integration Test', function (): void {
it('seeds default replicated Arcadia Oracle records into the database', function (): void {
// GIVEN
$connection = Config::string('database.arcadia_meta_model');
$seeder = new ArcadiaReplicateSeeder();
$seeder = new ArcadiaReplicateSeeder();
// WHEN
$seeder->run();
// THEN
expect(DB::connection($connection)->table(MetaUtilTable::name())->count())->toBeGreaterThan(0)
->and(DB::connection($connection)->table(RuPersonneSirhTable::name())->count())->toBeGreaterThan(0)
->and(DB::connection($connection)->table(MarqueTable::name())->count())->toBeGreaterThan(0)
->and(DB::connection($connection)->table(IncoTable::name())->count())->toBeGreaterThan(0)
->and(DB::connection($connection)->table(IncoCompoTable::name())->count())->toBeGreaterThan(0);
expect(MetaUtilFactory::count())->toBeGreaterThan(0)
->and(RuPersonneSirhFactory::count())->toBeGreaterThan(0)
->and(MarqueFactory::count())->toBeGreaterThan(0)
->and(IncoFactory::count())->toBeGreaterThan(0)
->and(IncoCompoFactory::count())->toBeGreaterThan(0);
});
});

View file

@ -6,11 +6,10 @@ namespace Tests\Integration\Database\Seeders;
use Database\Seeders\BrandSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Infra\Database\Models\ArcadiaBrand;
use Infra\Database\Models\Brand;
use Tests\TestCase;
covers(Brand::class, ArcadiaBrand::class);
covers(Brand::class);
uses(TestCase::class, RefreshDatabase::class);
@ -23,8 +22,7 @@ describe('BrandSeeder Integration Test', function (): void {
$seeder->run();
// THEN
expect(ArcadiaBrand::count())->toBe(6)
->and(Brand::count())->toBe(6);
expect(Brand::count())->toBe(12);
$brand = Brand::query()->where('uwil_public_id', 'LGL01')->first();
expect($brand)->not->toBeNull()

View file

@ -4,16 +4,14 @@ declare(strict_types=1);
namespace Tests\Integration\Database\Seeders;
use Database\ArcadiaReplicate\Factories\Refp\IncoFactory;
use Database\ArcadiaReplicate\Factories\Refp\MarqueFactory;
use Database\ArcadiaReplicate\Factories\Refp\RuPersonneSirhFactory;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Infra\Database\Models\ArcadiaBrand;
use Infra\Database\Models\Brand;
use Infra\Database\Models\Employee;
use Infra\Database\Models\IncoSheet;
use Tests\TestCase;
covers(Employee::class, IncoSheet::class, Brand::class, ArcadiaBrand::class);
uses(TestCase::class, RefreshDatabase::class);
describe('DatabaseSeeder Integration Test', function (): void {
@ -25,9 +23,9 @@ describe('DatabaseSeeder Integration Test', function (): void {
$seeder->run();
// THEN
expect(Employee::count())->toBeGreaterThan(0)
->and(IncoSheet::count())->toBeGreaterThan(0)
expect(RuPersonneSirhFactory::count())->toBeGreaterThan(0)
->and(IncoFactory::count())->toBeGreaterThan(0)
->and(Brand::count())->toBeGreaterThan(0)
->and(ArcadiaBrand::count())->toBeGreaterThan(0);
->and(MarqueFactory::count())->toBeGreaterThan(0);
});
});