Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e55772986b | |||
| 8793bb09d7 | |||
| 75de2a46f1 | |||
| 9fc641f93b | |||
| c252d648b8 | |||
| 9865c17ac8 | |||
| 26c5f06f98 | |||
| 33a23d0392 | |||
| 236ae4ab8c | |||
| 2675598eee | |||
| 16c0c594b1 | |||
| dedf5f1964 |
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"yaml.schemas": {
|
||||||
|
"file:///home/jfgiraud/.vscode-server/extensions/continue.continue-2.0.0-linux-x64/config-yaml-schema.json": [
|
||||||
|
".continue/**/*.yaml",
|
||||||
|
"file:///home/jfgiraud/.continue/config.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"json.schemas": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,692 @@
|
|||||||
|
isin,ticker,yahoo_code,company_name,updated_at
|
||||||
|
FR0011184241,ADOC,ADOC.PA,Adocia,"2026-07-02 13:36:06"
|
||||||
|
FR00140066X4,ALTHO,ALTHO.PA,Metavisio,"2026-07-02 13:31:23"
|
||||||
|
KR7005380001,005380,005380.KS,"Hyundai Motor Company","2026-07-02 12:40:35"
|
||||||
|
KR7005930003,005930,005930.KS,"Samsung Electronics Co., Ltd.","2026-07-02 11:03:20"
|
||||||
|
FR0000039109,SCHP,SCHP.PA,"Seche Environnement","2026-06-17 11:41:00"
|
||||||
|
DE000BAY0017,BAYN,BAYN.DE,"Bayer AG","2026-06-17 11:38:00"
|
||||||
|
DE000PASM111,P911,P911.DE,"Porsche AG","2026-06-17 11:38:00"
|
||||||
|
DK0062498110,NOVOB,NOVO-B.CO,"Novo Nordisk A/S","2026-06-17 11:38:00"
|
||||||
|
FR0000051732,ALTA,ALTA.PA,Altareit,"2026-06-17 11:38:00"
|
||||||
|
FR0000073298,ALT,ALT.PA,Alten,"2026-06-17 11:38:00"
|
||||||
|
GB0007188757,RIO,RIO.L,"Rio Tinto plc","2026-06-17 11:38:00"
|
||||||
|
NL0000009355,UNA,UNA.AS,"Unilever PLC","2026-06-17 11:38:00"
|
||||||
|
CH0012005267,NOVN,NOVN.SW,"Novartis AG","2026-06-17 11:35:00"
|
||||||
|
CH0038863350,NESN,NESN.SW,"Nestlé SA","2026-06-17 11:35:00"
|
||||||
|
DE0007100000,MBG,MBG.DE,"Mercedes-Benz Group","2026-06-17 11:35:00"
|
||||||
|
FR0000031122,AIRP,AIRP.PA,"Air France-KLM","2026-06-17 11:35:00"
|
||||||
|
FR0000035081,ICAD,ICAD.PA,Icade,"2026-06-17 11:35:00"
|
||||||
|
FR0000053381,VLA,VLA.PA,"Valneva SE","2026-06-17 11:35:00"
|
||||||
|
FR0010241639,ALM,ALM.PA,"McPhy Energy","2026-06-17 11:35:00"
|
||||||
|
GB00BP6MXD84,BP,BP.L,"BP plc","2026-06-17 11:35:00"
|
||||||
|
LU1598081501,MT,MT.PA,ArcelorMittal,"2026-06-17 11:35:00"
|
||||||
|
NL0015000H23,ASML,ASML.AS,"ASML Holding","2026-06-17 11:35:00"
|
||||||
|
FR001400IZY7,CO,CO.PA,"Casino Guichard Perrachon","2026-06-17 11:28:00"
|
||||||
|
ES0139140174,COL,COL.MC,"Colonial SFL, SOCIMI, S.A.","2026-06-17 08:00:34"
|
||||||
|
ES0177542018,IAG,IAG.MC,"International Consolidated Airlines Group (IAG)","2026-06-17 07:58:31"
|
||||||
|
US0000000BTC,BTC-USD,BTC-USD,"Bitcoin USD","2026-06-16 19:53:44"
|
||||||
|
US000000GOLD,GC=F,GC=F,"Gold Ounce","2026-06-16 19:53:44"
|
||||||
|
XC0009677409,BRN,BZ=F,"Brent Crude Oil","2026-06-16 19:53:44"
|
||||||
|
BMG0450A1053,ACGL,ACGL,"Arch Capital Group","2026-06-16 19:00:10"
|
||||||
|
CH0044328745,CB,CB,"Chubb Limited","2026-06-16 19:00:10"
|
||||||
|
IE00B4BNMY34,ACN,ACN,Accenture,"2026-06-16 19:00:10"
|
||||||
|
IE00B8KQN827,ETN,ETN,"Eaton Corporation","2026-06-16 19:00:10"
|
||||||
|
IE00B9699L58,ALLE,ALLE,Allegion,"2026-06-16 19:00:10"
|
||||||
|
IE00BLP1HW54,AON,AON,Aon,"2026-06-16 19:00:10"
|
||||||
|
JE00BJ1F3079,AMCR,AMCR,Amcor,"2026-06-16 19:00:10"
|
||||||
|
US0009041051,ADT,ADT,"ADT Inc.","2026-06-16 19:00:10"
|
||||||
|
US0010551028,AFL,AFL,Aflac,"2026-06-16 19:00:10"
|
||||||
|
US00130H1059,AES,AES,"AES Corporation","2026-06-16 19:00:10"
|
||||||
|
US0017651060,AAL,AAL,"American Airlines Group","2026-06-16 19:00:10"
|
||||||
|
US0028241000,ABT,ABT,"Abbott Laboratories","2026-06-16 19:00:10"
|
||||||
|
US00287Y1091,ABBV,ABBV,AbbVie,"2026-06-16 19:00:10"
|
||||||
|
US00846U1016,A,A,"Agilent Technologies","2026-06-16 19:00:10"
|
||||||
|
US0090661010,ABNB,ABNB,Airbnb,"2026-06-16 19:00:10"
|
||||||
|
US0091581068,APD,APD,"Air Products and Chemicals","2026-06-16 19:00:10"
|
||||||
|
US0097281069,AKAM,AKAM,Akamai,"2026-06-16 19:00:10"
|
||||||
|
US0126531013,ALB,ALB,"Albemarle Corporation","2026-06-16 19:00:10"
|
||||||
|
US0152711091,ARE,ARE,"Alexandria Real Estate Equities","2026-06-16 19:00:10"
|
||||||
|
US0162551016,ALGN,ALGN,"Align Technology","2026-06-16 19:00:10"
|
||||||
|
US0188021085,LNT,LNT,"Alliant Energy","2026-06-16 19:00:10"
|
||||||
|
US0200021014,ALL,ALL,Allstate,"2026-06-16 19:00:10"
|
||||||
|
US02209S1033,MO,MO,Altria,"2026-06-16 19:00:10"
|
||||||
|
US0231351067,AMZN,AMZN,Amazon,"2026-06-16 19:00:10"
|
||||||
|
US0236081024,AEE,AEE,Ameren,"2026-06-16 19:00:10"
|
||||||
|
US0255371017,AEP,AEP,"American Electric Power","2026-06-16 19:00:10"
|
||||||
|
US0268747849,AIG,AIG,"American International Group","2026-06-16 19:00:10"
|
||||||
|
US03027X1000,AMT,AMT,"American Tower","2026-06-16 19:00:10"
|
||||||
|
US0304201033,AWK,AWK,"American Water Works","2026-06-16 19:00:10"
|
||||||
|
US03076C1062,AMP,AMP,"Ameriprise Financial","2026-06-16 19:00:10"
|
||||||
|
US0311001004,AME,AME,Ametek,"2026-06-16 19:00:10"
|
||||||
|
US0320951017,APH,APH,Amphenol,"2026-06-16 19:00:10"
|
||||||
|
US0326541051,ADI,ADI,"Analog Devices","2026-06-16 19:00:10"
|
||||||
|
US03662Q1058,ANSS,ANSS,Ansys,"2026-06-16 19:00:10"
|
||||||
|
US0367521038,ELV,ELV,"Elevance Health","2026-06-16 19:00:10"
|
||||||
|
US03743Q1085,APA,APA,"APA Corporation","2026-06-16 19:00:10"
|
||||||
|
US03769M1062,APO,APO,"Apollo Global Management","2026-06-16 19:00:10"
|
||||||
|
US0382221051,AMAT,AMAT,"Applied Materials","2026-06-16 19:00:10"
|
||||||
|
US03831W1080,APP,APP,AppLovin,"2026-06-16 19:00:10"
|
||||||
|
US0394831020,ADM,ADM,Archer-Daniels-Midland,"2026-06-16 19:00:10"
|
||||||
|
US03990B1017,ARES,ARES,"Ares Management","2026-06-16 19:00:10"
|
||||||
|
US0404132054,ANET,ANET,"Arista Networks","2026-06-16 19:00:10"
|
||||||
|
US04586V1026,AIZ,AIZ,Assurant,"2026-06-16 19:00:10"
|
||||||
|
US0495601058,ATO,ATO,"Atmos Energy","2026-06-16 19:00:10"
|
||||||
|
US0527691069,ADSK,ADSK,Autodesk,"2026-06-16 19:00:10"
|
||||||
|
US0533321024,AZO,AZO,AutoZone,"2026-06-16 19:00:10"
|
||||||
|
US0534841012,AVB,AVB,"AvalonBay Communities","2026-06-16 19:00:10"
|
||||||
|
US0536111091,AVY,AVY,"Avery Dennison","2026-06-16 19:00:10"
|
||||||
|
US05464C1018,AXON,AXON,"Axon Enterprise","2026-06-16 19:00:10"
|
||||||
|
US0584981064,BALL,BALL,"Ball Corporation","2026-06-16 19:00:10"
|
||||||
|
US0605051046,BAC,BAC,"Bank of America","2026-06-16 19:00:10"
|
||||||
|
US0635761097,AJG,AJG,"Arthur J. Gallagher & Co.","2026-06-16 19:00:10"
|
||||||
|
US0640581007,BK,BK,"The Bank of New York Mellon","2026-06-16 19:00:10"
|
||||||
|
US0718131099,BAX,BAX,"Baxter International","2026-06-16 19:00:10"
|
||||||
|
US0758871014,BDX,BDX,"Becton Dickinson","2026-06-16 19:00:10"
|
||||||
|
US0846707026,BRK.B,BRK.B,"Berkshire Hathaway","2026-06-16 19:00:10"
|
||||||
|
US0865161014,BBY,BBY,"Best Buy","2026-06-16 19:00:10"
|
||||||
|
US09062X1037,BIIB,BIIB,Biogen,"2026-06-16 19:00:10"
|
||||||
|
US09290D1019,BLK,BLK,BlackRock,"2026-06-16 19:00:10"
|
||||||
|
US09857L1048,BKNG,BKNG,"Booking Holdings","2026-06-16 19:00:10"
|
||||||
|
US1011211018,BXP,BXP,"BXP, Inc.","2026-06-16 19:00:10"
|
||||||
|
US1011371077,BSX,BSX,"Boston Scientific","2026-06-16 19:00:10"
|
||||||
|
US1101221007,BMY,BMY,"Bristol Myers Squibb","2026-06-16 19:00:10"
|
||||||
|
US11133T1034,BR,BR,"Broadridge Financial Solutions","2026-06-16 19:00:10"
|
||||||
|
US1128071014,LRCX,LRCX,"Lam Research","2026-06-16 19:00:10"
|
||||||
|
US1152361010,BRO,BRO,"Brown & Brown","2026-06-16 19:00:10"
|
||||||
|
US1156372096,BF.B,BF.B,Brown-Forman,"2026-06-16 19:00:10"
|
||||||
|
US12008R1077,BLDR,BLDR,"Builders FirstSource","2026-06-16 19:00:10"
|
||||||
|
US12503M1080,CBOE,CBOE,"Cboe Global Markets","2026-06-16 19:00:10"
|
||||||
|
US12504L1098,CBRE,CBRE,"CBRE Group","2026-06-16 19:00:10"
|
||||||
|
US12514G1085,CDW,CDW,CDW,"2026-06-16 19:00:10"
|
||||||
|
US1252691001,CF,CF,"CF Industries","2026-06-16 19:00:10"
|
||||||
|
US12541W2098,CHRW,CHRW,"C.H. Robinson","2026-06-16 19:00:10"
|
||||||
|
US1255231003,CI,CI,"The Cigna Group","2026-06-16 19:00:10"
|
||||||
|
US12572Q1058,CME,CME,"CME Group","2026-06-16 19:00:10"
|
||||||
|
US1258961002,CMS,CMS,"CMS Energy","2026-06-16 19:00:10"
|
||||||
|
US1264081035,CSX,CSX,"CSX Corporation","2026-06-16 19:00:10"
|
||||||
|
US1273871087,CDNS,CDNS,"Cadence Design Systems","2026-06-16 19:00:10"
|
||||||
|
US1331311027,CPT,CPT,"Camden Property Trust","2026-06-16 19:00:10"
|
||||||
|
US1344291091,CPB,CPB,"Campbell Soup Company","2026-06-16 19:00:10"
|
||||||
|
US14040H1059,COF,COF,"Capital One","2026-06-16 19:00:10"
|
||||||
|
US14149Y1082,CAH,CAH,"Cardinal Health","2026-06-16 19:00:10"
|
||||||
|
US14448C1045,CARR,CARR,"Carrier Global","2026-06-16 19:00:10"
|
||||||
|
US1468691027,CVNA,CVNA,Carvana,"2026-06-16 19:00:10"
|
||||||
|
US1475281036,CASY,CASY,"Casey's General Stores","2026-06-16 19:00:10"
|
||||||
|
US1491231015,CAT,CAT,"Caterpillar Inc.","2026-06-16 19:00:10"
|
||||||
|
US1508701034,CE,CE,Celanese,"2026-06-16 19:00:10"
|
||||||
|
US15135B1017,CNC,CNC,"Centene Corporation","2026-06-16 19:00:10"
|
||||||
|
US15189T1079,CNP,CNP,"CenterPoint Energy","2026-06-16 19:00:10"
|
||||||
|
US1598641074,CRL,CRL,"Charles River Laboratories","2026-06-16 19:00:10"
|
||||||
|
US16119P1084,CHTR,CHTR,"Charter Communications","2026-06-16 19:00:10"
|
||||||
|
US1696561059,CMG,CMG,"Chipotle Mexican Grill","2026-06-16 19:00:10"
|
||||||
|
US1713401024,CHD,CHD,"Church & Dwight","2026-06-16 19:00:10"
|
||||||
|
US1717791016,CIEN,CIEN,Ciena,"2026-06-16 19:00:10"
|
||||||
|
US1720621010,CINF,CINF,"Cincinnati Financial","2026-06-16 19:00:10"
|
||||||
|
US17275R1023,CSCO,CSCO,Cisco,"2026-06-16 19:00:10"
|
||||||
|
US1729081035,CTAS,CTAS,Cintas,"2026-06-16 19:00:10"
|
||||||
|
US1729674242,C,C,Citigroup,"2026-06-16 19:00:10"
|
||||||
|
US1746101054,CFG,CFG,"Citizens Financial Group","2026-06-16 19:00:10"
|
||||||
|
US1890541097,CLX,CLX,Clorox,"2026-06-16 19:00:10"
|
||||||
|
US19247G1076,COHR,COHR,Coherent,"2026-06-16 19:00:10"
|
||||||
|
US19260U1051,COIN,COIN,Coinbase,"2026-06-16 19:00:10"
|
||||||
|
US1941621039,CL,CL,Colgate-Palmolive,"2026-06-16 19:00:10"
|
||||||
|
US1999081045,FIX,FIX,"Comfort Systems USA","2026-06-16 19:00:10"
|
||||||
|
US2003401070,CMA,CMA,Comerica,"2026-06-16 19:00:10"
|
||||||
|
US20825C1045,COP,COP,ConocoPhillips,"2026-06-16 19:00:10"
|
||||||
|
US2091151041,ED,ED,"Consolidated Edison","2026-06-16 19:00:10"
|
||||||
|
US21037T1097,CEG,CEG,"Constellation Energy","2026-06-16 19:00:10"
|
||||||
|
US21664A1025,COO,COO,"The Cooper Companies","2026-06-16 19:00:10"
|
||||||
|
US2172041061,CPRT,CPRT,Copart,"2026-06-16 19:00:10"
|
||||||
|
US22052L1044,CTVA,CTVA,Corteva,"2026-06-16 19:00:10"
|
||||||
|
US22160N1090,CSGP,CSGP,"CoStar Group","2026-06-16 19:00:10"
|
||||||
|
US22788C1053,CRWD,CRWD,CrowdStrike,"2026-06-16 19:00:10"
|
||||||
|
US2283681060,CCK,CCK,"Crown Holdings","2026-06-16 19:00:10"
|
||||||
|
US2310211063,CMI,CMI,Cummins,"2026-06-16 19:00:10"
|
||||||
|
US23331A1097,DHI,DHI,"D.R. Horton","2026-06-16 19:00:10"
|
||||||
|
US2333311072,DTE,DTE,"DTE Energy","2026-06-16 19:00:10"
|
||||||
|
US2371941053,DRI,DRI,"Darden Restaurants","2026-06-16 19:00:10"
|
||||||
|
US23804L1035,DDOG,DDOG,Datadog,"2026-06-16 19:00:10"
|
||||||
|
US23918K1088,DVA,DVA,"DaVita Inc.","2026-06-16 19:00:10"
|
||||||
|
US2441991054,DE,DE,"John Deere","2026-06-16 19:00:10"
|
||||||
|
US24703L2025,DELL,DELL,"Dell Technologies","2026-06-16 19:00:10"
|
||||||
|
US2473617023,DAL,DAL,"Delta Air Lines","2026-06-16 19:00:10"
|
||||||
|
US25179M1036,DVN,DVN,"Devon Energy","2026-06-16 19:00:10"
|
||||||
|
US2521311074,DXCM,DXCM,Dexcom,"2026-06-16 19:00:10"
|
||||||
|
US25278X1090,FANG,FANG,"Diamondback Energy","2026-06-16 19:00:10"
|
||||||
|
US2546871060,DIS,DIS,"Walt Disney","2026-06-16 19:00:10"
|
||||||
|
US2567461080,DLTR,DLTR,"Dollar Tree","2026-06-16 19:00:10"
|
||||||
|
US25746U1097,DOV,DOV,"Dover Corporation","2026-06-16 19:00:10"
|
||||||
|
US25754A2015,DPZ,DPZ,Domino's,"2026-06-16 19:00:10"
|
||||||
|
US26441C2044,DUK,DUK,"Duke Energy","2026-06-16 19:00:10"
|
||||||
|
US26614N1028,DD,DD,DuPont,"2026-06-16 19:00:10"
|
||||||
|
US26875P1012,EOG,EOG,"EOG Resources","2026-06-16 19:00:10"
|
||||||
|
US26884L1098,EQT,EQT,"EQT Corporation","2026-06-16 19:00:10"
|
||||||
|
US2788651006,ECL,ECL,Ecolab,"2026-06-16 19:00:10"
|
||||||
|
US2810201077,EIX,EIX,"Edison International","2026-06-16 19:00:10"
|
||||||
|
US28176E1082,EW,EW,"Edwards Lifesciences","2026-06-16 19:00:10"
|
||||||
|
US2855121099,EA,EA,"Electronic Arts","2026-06-16 19:00:10"
|
||||||
|
US29084Q1004,EME,EME,"EMCOR Group","2026-06-16 19:00:10"
|
||||||
|
US2910111044,EMR,EMR,"Emerson Electric","2026-06-16 19:00:10"
|
||||||
|
US29364G1031,ETR,ETR,Entergy,"2026-06-16 19:00:10"
|
||||||
|
US29414B1044,EPAM,EPAM,"EPAM Systems","2026-06-16 19:00:10"
|
||||||
|
US2944291051,EFX,EFX,Equifax,"2026-06-16 19:00:10"
|
||||||
|
US29476L1070,EQR,EQR,"Equity Residential","2026-06-16 19:00:10"
|
||||||
|
US29530P1021,ERIE,ERIE,"Erie Indemnity","2026-06-16 19:00:10"
|
||||||
|
US2971721029,ESS,ESS,"Essex Property Trust","2026-06-16 19:00:10"
|
||||||
|
US30034W1062,EVRG,EVRG,Evergy,"2026-06-16 19:00:10"
|
||||||
|
US30161N1019,EXE,EXE,"Expand Energy","2026-06-16 19:00:10"
|
||||||
|
US3021301094,EXPD,EXPD,"Expeditors International","2026-06-16 19:00:10"
|
||||||
|
US30225T1025,EXR,EXR,"Extra Space Storage","2026-06-16 19:00:10"
|
||||||
|
US3024913036,FMC,FMC,"FMC Corporation","2026-06-16 19:00:10"
|
||||||
|
US3030751057,FDS,FDS,FactSet,"2026-06-16 19:00:10"
|
||||||
|
US3032501047,FICO,FICO,"Fair Isaac","2026-06-16 19:00:10"
|
||||||
|
US3119001044,FAST,FAST,Fastenal,"2026-06-16 19:00:10"
|
||||||
|
US3137451015,FRT,FRT,"Federal Realty","2026-06-16 19:00:10"
|
||||||
|
US31428X1063,FDX,FDX,FedEx,"2026-06-16 19:00:10"
|
||||||
|
US3156161024,FFIV,FFIV,"F5, Inc.","2026-06-16 19:00:10"
|
||||||
|
US3167731005,FITB,FITB,"Fifth Third Bank","2026-06-16 19:00:10"
|
||||||
|
US3364331070,FLT,FLT,"Business Fuel Cards (Corpay)","2026-06-16 19:00:10"
|
||||||
|
US3379321074,FE,FE,FirstEnergy,"2026-06-16 19:00:10"
|
||||||
|
US34959E1091,FTNT,FTNT,Fortinet,"2026-06-16 19:00:10"
|
||||||
|
US34959J1084,FTV,FTV,Fortive,"2026-06-16 19:00:10"
|
||||||
|
US35137L1052,FOXA,FOXA,"Fox Corporation (Class A)","2026-06-16 19:00:10"
|
||||||
|
US35137L2043,FOX,FOX,"Fox Corporation (Class B)","2026-06-16 19:00:10"
|
||||||
|
US3546131018,BEN,BEN,"Franklin Templeton","2026-06-16 19:00:10"
|
||||||
|
US35671D8570,FCX,FCX,Freeport-McMoRan,"2026-06-16 19:00:10"
|
||||||
|
US36266G1076,GEHC,GEHC,"GE HealthCare","2026-06-16 19:00:10"
|
||||||
|
US3666511072,IT,IT,Gartner,"2026-06-16 19:00:10"
|
||||||
|
US3695501086,GD,GD,"General Dynamics","2026-06-16 19:00:10"
|
||||||
|
US3696043013,GEV,GEV,"GE Vernova","2026-06-16 19:00:10"
|
||||||
|
US3703341046,GIS,GIS,"General Mills","2026-06-16 19:00:10"
|
||||||
|
US37045V1008,GM,GM,"General Motors","2026-06-16 19:00:10"
|
||||||
|
US3746891040,GPC,GPC,"Genuine Parts Company","2026-06-16 19:00:10"
|
||||||
|
US37940X1028,GPN,GPN,"Global Payments","2026-06-16 19:00:10"
|
||||||
|
US37959E1029,GL,GL,"Globe Life","2026-06-16 19:00:10"
|
||||||
|
US3802371076,GNDY,GNDY,GoDaddy,"2026-06-16 19:00:10"
|
||||||
|
US38141G1040,GS,GS,"Goldman Sachs","2026-06-16 19:00:10"
|
||||||
|
US3848021040,GWW,GWW,"W. W. Grainger","2026-06-16 19:00:10"
|
||||||
|
US40412C1018,HCA,HCA,"HCA Healthcare","2026-06-16 19:00:10"
|
||||||
|
US40434L1052,HPQ,HPQ,"HP Inc.","2026-06-16 19:00:10"
|
||||||
|
US4165151048,HIG,HIG,"The Hartford","2026-06-16 19:00:10"
|
||||||
|
US42250P1030,DOC,DOC,"Healthpeak Properties","2026-06-16 19:00:10"
|
||||||
|
US4262811015,JKHY,JKHY,"Jack Henry & Associates","2026-06-16 19:00:10"
|
||||||
|
US4278661081,HSY,HSY,"The Hershey Company","2026-06-16 19:00:10"
|
||||||
|
US43300A2033,HD,HD,"Home Depot","2026-06-16 19:00:10"
|
||||||
|
US4404521001,HRL,HRL,"Hormel Foods","2026-06-16 19:00:10"
|
||||||
|
US44107P1049,HST,HST,"Host Hotels & Resorts","2026-06-16 19:00:10"
|
||||||
|
US4432011082,HWM,HWM,"Howmet Aerospace","2026-06-16 19:00:10"
|
||||||
|
US4435106079,HUBB,HUBB,"Hubbell Incorporated","2026-06-16 19:00:10"
|
||||||
|
US4448591028,HUM,HUM,Humana,"2026-06-16 19:00:10"
|
||||||
|
US4456581077,JBHT,JBHT,"J.B. Hunt","2026-06-16 19:00:10"
|
||||||
|
US4461501045,HBAN,HBAN,"Huntington Bancshares","2026-06-16 19:00:10"
|
||||||
|
US4464131063,HII,HII,"Huntington Ingalls Industries","2026-06-16 19:00:10"
|
||||||
|
US45168D1046,IDXX,IDXX,"IDEXX Laboratories","2026-06-16 19:00:10"
|
||||||
|
US4553708600,F,F,"Ford Motor Company","2026-06-16 19:00:10"
|
||||||
|
US45687V1061,IR,IR,"Ingersoll Rand","2026-06-16 19:00:10"
|
||||||
|
US45841N1072,IBKR,IBKR,"Interactive Brokers","2026-06-16 19:00:10"
|
||||||
|
US45866F1043,ICE,ICE,"Intercontinental Exchange","2026-06-16 19:00:10"
|
||||||
|
US4592001014,IBM,IBM,IBM,"2026-06-16 19:00:10"
|
||||||
|
US4595061015,IFF,IFF,"International Flavors & Fragrances","2026-06-16 19:00:10"
|
||||||
|
US4601461035,IP,IP,"International Paper","2026-06-16 19:00:10"
|
||||||
|
US46120E6023,ISRG,ISRG,"Intuitive Surgical","2026-06-16 19:00:10"
|
||||||
|
US46187W1071,INVH,INVH,"Invitation Homes","2026-06-16 19:00:10"
|
||||||
|
US46266C1053,IQV,IQV,IQVIA,"2026-06-16 19:00:10"
|
||||||
|
US46284V1017,IRM,IRM,"Iron Mountain","2026-06-16 19:00:10"
|
||||||
|
US46625H1005,JPM,JPM,"JPMorgan Chase","2026-06-16 19:00:10"
|
||||||
|
US4663131039,JBL,JBL,Jabil,"2026-06-16 19:00:10"
|
||||||
|
US46982L1089,J,J,"Jacobs Solutions","2026-06-16 19:00:10"
|
||||||
|
US49177J1025,KVUE,KVUE,Kenvue,"2026-06-16 19:00:10"
|
||||||
|
US49271V1008,KDP,KDP,"Keurig Dr Pepper","2026-06-16 19:00:10"
|
||||||
|
US4932671088,KEY,KEY,KeyCorp,"2026-06-16 19:00:10"
|
||||||
|
US49338L1035,KEYS,KEYS,Keysight,"2026-06-16 19:00:10"
|
||||||
|
US4943681035,KMB,KMB,Kimberly-Clark,"2026-06-16 19:00:10"
|
||||||
|
US49446R1095,KIM,KIM,"Kimco Realty","2026-06-16 19:00:10"
|
||||||
|
US49456B1017,KMI,KMI,"Kinder Morgan","2026-06-16 19:00:10"
|
||||||
|
US5010441013,KR,KR,Kroger,"2026-06-16 19:00:10"
|
||||||
|
US5024311095,LHX,LHX,L3Harris,"2026-06-16 19:00:10"
|
||||||
|
US5049221055,LH,LH,Labcorp,"2026-06-16 19:00:10"
|
||||||
|
US5178341070,LVS,LVS,"Las Vegas Sands","2026-06-16 19:00:10"
|
||||||
|
US5184391044,EL,EL,"Estée Lauder Companies","2026-06-16 19:00:10"
|
||||||
|
US5253271028,LDOS,LDOS,Leidos,"2026-06-16 19:00:10"
|
||||||
|
US5260571048,LEN,LEN,Lennar,"2026-06-16 19:00:10"
|
||||||
|
US5261071071,LII,LII,"Lennox International","2026-06-16 19:00:10"
|
||||||
|
US5380341090,LYV,LYV,"Live Nation Entertainment","2026-06-16 19:00:10"
|
||||||
|
US5398301094,LMT,LMT,"Lockheed Martin","2026-06-16 19:00:10"
|
||||||
|
US5404241031,L,L,"Loews Corporation","2026-06-16 19:00:10"
|
||||||
|
US5500211090,LULU,LULU,"Lululemon Athletica","2026-06-16 19:00:10"
|
||||||
|
US55024U1097,LITE,LITE,Lumentum,"2026-06-16 19:00:10"
|
||||||
|
US55261F1043,MTB,MTB,"M&T Bank","2026-06-16 19:00:10"
|
||||||
|
US5529531015,MGM,MGM,"MGM Resorts","2026-06-16 19:00:10"
|
||||||
|
US55354G1004,MSCI,MSCI,"MSCI Inc.","2026-06-16 19:00:10"
|
||||||
|
US5717481023,MRSH,MRSH,"Marsh & McLennan","2026-06-16 19:00:10"
|
||||||
|
US66987P1012,ES,ES,"Eversource Energy","2026-06-16 19:00:10"
|
||||||
|
US74834L1008,DGX,DGX,"Quest Diagnostics","2026-06-16 19:00:10"
|
||||||
|
US77313F1066,HOOD,HOOD,"Robinhood Markets","2026-06-16 19:00:10"
|
||||||
|
US78430Q1013,AOS,AOS,"A. O. Smith","2026-06-16 19:00:10"
|
||||||
|
US78464A6982,KRE,KRE,"SPDR S&P Regional Banking","2026-06-16 19:00:10"
|
||||||
|
US79466L3024,CRM,CRM,Salesforce,"2026-06-16 19:00:10"
|
||||||
|
US89235Q1011,SQ,SQ,"Block, Inc.","2026-06-16 19:00:10"
|
||||||
|
US9892071054,ZBRA,ZBRA,"Zebra Technologies","2026-06-16 19:00:10"
|
||||||
|
BMG667211046,NCLH,NCLH,"Norwegian Cruise Line Holdings","2026-06-16 18:51:11"
|
||||||
|
CH0102993182,TEL,TEL,"TE Connectivity","2026-06-16 18:51:11"
|
||||||
|
IE000S9YS062,SW,SW,"Smurfit Westrock","2026-06-16 18:51:11"
|
||||||
|
IE00B58JVZ52,STX,STX,"Seagate Technology","2026-06-16 18:51:11"
|
||||||
|
IE00BDB64S84,WTW,WTW,"Willis Towers Watson","2026-06-16 18:51:11"
|
||||||
|
US4062161017,HAL,HAL,Halliburton,"2026-06-16 18:51:11"
|
||||||
|
US42824C1099,HPE,HPE,"Hewlett Packard Enterprise","2026-06-16 18:51:11"
|
||||||
|
US45784P1012,PODD,PODD,"Insulet Corporation","2026-06-16 18:51:11"
|
||||||
|
US4781281010,SJM,SJM,"J.M. Smucker Company (The)","2026-06-16 18:51:11"
|
||||||
|
US60871R1023,TAP,TAP,"Molson Coors Beverage Company","2026-06-16 18:51:11"
|
||||||
|
US61174X1090,MNST,MNST,"Monster Beverage","2026-06-16 18:51:11"
|
||||||
|
US61945C1036,MOS,MOS,"Mosaic Company (The)","2026-06-16 18:51:11"
|
||||||
|
US6556631008,NDSN,NDSN,"Nordson Corporation","2026-06-16 18:51:11"
|
||||||
|
US6558441084,NSC,NSC,"Norfolk Southern","2026-06-16 18:51:11"
|
||||||
|
US6658591044,NTRS,NTRS,"Northern Trust","2026-06-16 18:51:11"
|
||||||
|
US6687711084,NOC,NOC,"Northrop Grumman","2026-06-16 18:51:11"
|
||||||
|
US6703461052,NUE,NUE,Nucor,"2026-06-16 18:51:11"
|
||||||
|
US6745991058,OXY,OXY,"Occidental Petroleum","2026-06-16 18:51:11"
|
||||||
|
US6821891057,ON,ON,"ON Semiconductor","2026-06-16 18:51:11"
|
||||||
|
US6852181040,ORLY,ORLY,"O’Reilly Automotive","2026-06-16 18:51:11"
|
||||||
|
US69331C1080,PCG,PCG,"PG&E Corporation","2026-06-16 18:51:11"
|
||||||
|
US6951561090,PKG,PKG,"Packaging Corporation of America","2026-06-16 18:51:11"
|
||||||
|
US69608A1088,PLTR,PLTR,"Palantir Technologies","2026-06-16 18:51:11"
|
||||||
|
US7010941042,PH,PH,"Parker Hannifin","2026-06-16 18:51:11"
|
||||||
|
US7234841010,PNW,PNW,"Pinnacle West Capital","2026-06-16 18:51:11"
|
||||||
|
US7433151039,PGR,PGR,"Progressive Corporation","2026-06-16 18:51:11"
|
||||||
|
US74624M1027,RL,RL,"Ralph Lauren Corporation","2026-06-16 18:51:11"
|
||||||
|
US74955A1051,RVTY,RVTY,Revvity,"2026-06-16 18:51:11"
|
||||||
|
US7588491032,REG,REG,"Regency Centers","2026-06-16 18:51:11"
|
||||||
|
US7591EP1011,RF,RF,"Regions Financial Corporation","2026-06-16 18:51:11"
|
||||||
|
US8085131055,SCHW,SCHW,"Charles Schwab Corporation","2026-06-16 18:51:11"
|
||||||
|
US8168511090,SRE,SRE,Sempra,"2026-06-16 18:51:11"
|
||||||
|
US8243481061,SHW,SHW,Sherwin-Williams,"2026-06-16 18:51:11"
|
||||||
|
US8330341012,SNA,SNA,Snap-on,"2026-06-16 18:51:11"
|
||||||
|
US84574X1019,SOLV,SOLV,Solventum,"2026-06-16 18:51:11"
|
||||||
|
US8574771031,STT,STT,"State Street Corporation","2026-06-16 18:51:11"
|
||||||
|
US8591521005,STE,STE,Steris,"2026-06-16 18:51:11"
|
||||||
|
US8718291030,SYY,SYY,Sysco,"2026-06-16 18:51:11"
|
||||||
|
US8760301072,TPR,TPR,"Tapestry, Inc.","2026-06-16 18:51:11"
|
||||||
|
US87612G1013,TRGP,TRGP,"Targa Resources","2026-06-16 18:51:11"
|
||||||
|
US8793601058,TDY,TDY,"Teledyne Technologies","2026-06-16 18:51:11"
|
||||||
|
US88262P1021,TPL,TPL,"Texas Pacific Land Corporation","2026-06-16 18:51:11"
|
||||||
|
US8932351081,TDG,TDG,"TransDigm Group","2026-06-16 18:51:11"
|
||||||
|
US89417E1091,TRV,TRV,"Travelers Companies (The)","2026-06-16 18:51:11"
|
||||||
|
US8962391004,TRMB,TRMB,"Trimble Inc.","2026-06-16 18:51:11"
|
||||||
|
US9253401031,VRT,VRT,Vertiv,"2026-06-16 18:51:11"
|
||||||
|
US92556H2067,PSKY,PSKY,"Paramount Skydance Corporation","2026-06-16 18:51:11"
|
||||||
|
US9293251000,WRB,WRB,"W. R. Berkley Corporation","2026-06-16 18:51:11"
|
||||||
|
US9344231041,WBD,WBD,"Warner Bros. Discovery","2026-06-16 18:51:11"
|
||||||
|
US9418481035,WAT,WAT,"Waters Corporation","2026-06-16 18:51:11"
|
||||||
|
US9581021055,WDC,WDC,"Western Digital","2026-06-16 18:51:11"
|
||||||
|
US9621661089,WY,WY,Weyerhaeuser,"2026-06-16 18:51:11"
|
||||||
|
US9694571004,WMB,WMB,"Williams Companies","2026-06-16 18:51:11"
|
||||||
|
US9078181081,UNP,UNP,"Union Pacific Corporation","2026-06-16 18:28:11"
|
||||||
|
US92047W1018,VLO,VLO,"Valero Energy","2026-06-16 18:28:11"
|
||||||
|
US9290421011,VMC,VMC,"Vulcan Materials Company","2026-06-16 18:28:11"
|
||||||
|
US8425871071,SO,SO,"Southern Company","2026-06-16 18:28:08"
|
||||||
|
US30231G1022,XOM,XOM,ExxonMobil,"2026-06-16 18:27:40"
|
||||||
|
US7427181094,PG,PG,"Procter & Gamble","2026-06-16 18:27:26"
|
||||||
|
US5719032022,MAR,MAR,"Marriott International","2026-06-16 18:27:17"
|
||||||
|
US5745991068,MAS,MAS,Masco,"2026-06-16 18:27:17"
|
||||||
|
US57636Q1040,MA,MA,Mastercard,"2026-06-16 18:27:17"
|
||||||
|
US5825211047,MKC,MKC,"McCormick & Company","2026-06-16 18:27:17"
|
||||||
|
US5950171042,MCHP,MCHP,"Microchip Technology","2026-06-16 18:27:17"
|
||||||
|
US6092071563,MDLZ,MDLZ,"Mondelez International","2026-06-16 18:27:17"
|
||||||
|
US6098391054,MCO,MCO,"Moody's Corporation","2026-06-16 18:27:17"
|
||||||
|
US8447411088,LUV,LUV,"Southwest Airlines","2026-06-16 18:27:17"
|
||||||
|
US88579Y1010,MMM,MMM,3M,"2026-06-16 18:27:17"
|
||||||
|
US15135U1097,COR,COR,Cencora,"2026-06-16 18:26:35"
|
||||||
|
BM1250141022,BG,BG,"Bunge Global","2026-06-16 18:22:24"
|
||||||
|
US09260D1072,BX,BX,"Blackstone Inc.","2026-06-16 18:22:24"
|
||||||
|
BMG2004J1036,CCL,CCL,"Carnival Corporation","2026-06-16 17:05:54"
|
||||||
|
BMG3223R1088,EG,EG,"Everest Group","2026-06-16 17:05:54"
|
||||||
|
BMG491BT1088,IVZ,IVZ,Invesco,"2026-06-16 17:05:54"
|
||||||
|
CA8000541083,SNDK,SNDK,Sandisk,"2026-06-16 17:05:54"
|
||||||
|
IE0001827041,CRH,CRH,"CRH plc","2026-06-16 17:05:54"
|
||||||
|
IE000S9YS762,LIN,LIN,"Linde plc","2026-06-16 17:05:54"
|
||||||
|
IE00BK9ZQ967,TT,TT,"Trane Technologies","2026-06-16 17:05:54"
|
||||||
|
IE00BLS09M33,PNR,PNR,Pentair,"2026-06-16 17:05:54"
|
||||||
|
IE00BTN1Y115,MDT,MDT,Medtronic,"2026-06-16 17:05:54"
|
||||||
|
IE00BY7QL619,JCI,JCI,"Johnson Controls","2026-06-16 17:05:54"
|
||||||
|
JE00BTDN8H13,APTV,APTV,Aptiv,"2026-06-16 17:05:54"
|
||||||
|
JP3832370005,NWS,NWS,"News Corp (Class B)","2026-06-16 17:05:54"
|
||||||
|
LR0008862868,RCL,RCL,"Royal Caribbean Group","2026-06-16 17:05:54"
|
||||||
|
NL0009434992,LYB,LYB,LyondellBasell,"2026-06-16 17:05:54"
|
||||||
|
NL0009538784,NXPI,NXPI,"NXP Semiconductors","2026-06-16 17:05:54"
|
||||||
|
US00206R1023,T,T,AT&T,"2026-06-16 17:05:54"
|
||||||
|
US0530151036,ADP,ADP,"Automatic Data Processing","2026-06-16 17:05:54"
|
||||||
|
US05722G1004,BKR,BKR,"Baker Hughes","2026-06-16 17:05:54"
|
||||||
|
US09073M1045,TECH,TECH,Bio-Techne,"2026-06-16 17:05:54"
|
||||||
|
US21036P1084,STZ,STZ,"Constellation Brands","2026-06-16 17:05:54"
|
||||||
|
US2538681030,DLR,DLR,"Digital Realty","2026-06-16 17:05:54"
|
||||||
|
US3143521058,FDXF,FDXF,"FedEx Freight","2026-06-16 17:05:54"
|
||||||
|
US3687361044,GNRC,GNRC,Generac,"2026-06-16 17:05:54"
|
||||||
|
US4432011017,HON,HON,Honeywell,"2026-06-16 17:05:54"
|
||||||
|
US5732841060,MLM,MLM,"Martin Marietta Materials","2026-06-16 17:05:54"
|
||||||
|
US59156R1086,MET,MET,MetLife,"2026-06-16 17:05:54"
|
||||||
|
US5926881054,MTD,MTD,"Mettler Toledo","2026-06-16 17:05:54"
|
||||||
|
US59522J1034,MAA,MAA,"Mid-America Apartment Communities","2026-06-16 17:05:54"
|
||||||
|
US60770K1079,MRNA,MRNA,Moderna,"2026-06-16 17:05:54"
|
||||||
|
US6174464486,MS,MS,"Morgan Stanley","2026-06-16 17:05:54"
|
||||||
|
US6200763075,MSI,MSI,"Motorola Solutions","2026-06-16 17:05:54"
|
||||||
|
US6293775085,NRG,NRG,"NRG Energy","2026-06-16 17:05:54"
|
||||||
|
US6311031081,NDAQ,NDAQ,"Nasdaq, Inc.","2026-06-16 17:05:54"
|
||||||
|
US64110D1046,NTAP,NTAP,NetApp,"2026-06-16 17:05:54"
|
||||||
|
US64110L1061,NFLX,NFLX,Netflix,"2026-06-16 17:05:54"
|
||||||
|
US65473P1057,NI,NI,NiSource,"2026-06-16 17:05:54"
|
||||||
|
US6795801009,ODFL,ODFL,"Old Dominion","2026-06-16 17:05:54"
|
||||||
|
US6819191064,OMC,OMC,"Omnicom Group","2026-06-16 17:05:54"
|
||||||
|
US6826801036,OKE,OKE,Oneok,"2026-06-16 17:05:54"
|
||||||
|
US68902V1070,OTIS,OTIS,"Otis Worldwide","2026-06-16 17:05:54"
|
||||||
|
US6934751057,PNC,PNC,"PNC Financial Services","2026-06-16 17:05:54"
|
||||||
|
US69351T1060,PPL,PPL,"PPL Corporation","2026-06-16 17:05:54"
|
||||||
|
US69370C1009,PTC,PTC,"PTC Inc.","2026-06-16 17:05:54"
|
||||||
|
US6937181088,PCAR,PCAR,Paccar,"2026-06-16 17:05:54"
|
||||||
|
US6974351057,PANW,PANW,"Palo Alto Networks","2026-06-16 17:05:54"
|
||||||
|
US7043261079,PAYX,PAYX,Paychex,"2026-06-16 17:05:54"
|
||||||
|
US7181721090,PM,PM,"Philip Morris International","2026-06-16 17:05:54"
|
||||||
|
US7185461040,PSX,PSX,"Phillips 66","2026-06-16 17:05:54"
|
||||||
|
US73278L1052,POOL,POOL,"Pool Corporation","2026-06-16 17:05:54"
|
||||||
|
US74144T1088,TROW,TROW,"T. Rowe Price","2026-06-16 17:05:54"
|
||||||
|
US74340W1036,PLD,PLD,Prologis,"2026-06-16 17:05:54"
|
||||||
|
US7443201022,PRU,PRU,"Prudential Financial","2026-06-16 17:05:54"
|
||||||
|
US7445731067,PEG,PEG,"Public Service Enterprise Group","2026-06-16 17:05:54"
|
||||||
|
US74460D1090,PSA,PSA,"Public Storage","2026-06-16 17:05:54"
|
||||||
|
US74762E1029,PWR,PWR,"Quanta Services","2026-06-16 17:05:54"
|
||||||
|
US7547301090,RJF,RJF,"Raymond James Financial","2026-06-16 17:05:54"
|
||||||
|
US75513E1010,RTX,RTX,"RTX Corporation","2026-06-16 17:05:54"
|
||||||
|
US75886F1075,REGN,REGN,"Regeneron Pharmaceuticals","2026-06-16 17:05:54"
|
||||||
|
US7607591002,RSG,RSG,"Republic Services","2026-06-16 17:05:54"
|
||||||
|
US7611521078,RMD,RMD,ResMed,"2026-06-16 17:05:54"
|
||||||
|
US7739031091,ROK,ROK,"Rockwell Automation","2026-06-16 17:05:54"
|
||||||
|
US7757111049,ROL,ROL,"Rollins, Inc.","2026-06-16 17:05:54"
|
||||||
|
US7766961061,ROP,ROP,"Roper Technologies","2026-06-16 17:05:54"
|
||||||
|
US7782961038,ROST,ROST,"Ross Stores","2026-06-16 17:05:54"
|
||||||
|
US78410G1040,SBAC,SBAC,"SBA Communications","2026-06-16 17:05:54"
|
||||||
|
US8064071025,HSIC,HSIC,"Henry Schein","2026-06-16 17:05:54"
|
||||||
|
US81762P1021,NOW,NOW,ServiceNow,"2026-06-16 17:05:54"
|
||||||
|
US8288061091,SPG,SPG,"Simon Property Group","2026-06-16 17:05:54"
|
||||||
|
US83088M1027,SWKS,SWKS,"Skyworks Solutions","2026-06-16 17:05:54"
|
||||||
|
US8545021011,SWK,SWK,"Stanley Black & Decker","2026-06-16 17:05:54"
|
||||||
|
US8581191009,STLD,STLD,"Steel Dynamics","2026-06-16 17:05:54"
|
||||||
|
US86800U3023,SMCI,SMCI,Supermicro,"2026-06-16 17:05:54"
|
||||||
|
US8716071076,SNPS,SNPS,Synopsys,"2026-06-16 17:05:54"
|
||||||
|
US87165B1035,SYF,SYF,"Synchrony Financial","2026-06-16 17:05:54"
|
||||||
|
US8725401090,TJX,TJX,"TJX Companies","2026-06-16 17:05:54"
|
||||||
|
US87256C1018,TKO,TKO,"TKO Group Holdings","2026-06-16 17:05:54"
|
||||||
|
US8807701029,TER,TER,Teradyne,"2026-06-16 17:05:54"
|
||||||
|
US8832031012,TXT,TXT,Textron,"2026-06-16 17:05:54"
|
||||||
|
US88339J1051,TTD,TTD,"Trade Desk (The)","2026-06-16 17:05:54"
|
||||||
|
US8835561023,TMO,TMO,"Thermo Fisher Scientific","2026-06-16 17:05:54"
|
||||||
|
US89832Q1094,TFC,TFC,"Truist Financial","2026-06-16 17:05:54"
|
||||||
|
US9022521051,TYL,TYL,"Tyler Technologies","2026-06-16 17:05:54"
|
||||||
|
US9024941034,TSN,TSN,"Tyson Foods","2026-06-16 17:05:54"
|
||||||
|
US9026531049,UDR,UDR,"UDR, Inc.","2026-06-16 17:05:54"
|
||||||
|
US9029733048,USB,USB,"U.S. Bancorp","2026-06-16 17:05:54"
|
||||||
|
US90353T1007,UBER,UBER,Uber,"2026-06-16 17:05:54"
|
||||||
|
US90384S3031,ULTA,ULTA,"Ulta Beauty","2026-06-16 17:05:54"
|
||||||
|
US9100471096,UAL,UAL,"United Airlines Holdings","2026-06-16 17:05:54"
|
||||||
|
US9113631090,URI,URI,"United Rentals","2026-06-16 17:05:54"
|
||||||
|
US9139031002,UHS,UHS,"Universal Health Services","2026-06-16 17:05:54"
|
||||||
|
US9224751084,VEEV,VEEV,"Veeva Systems","2026-06-16 17:05:54"
|
||||||
|
US92276F1003,VTR,VTR,Ventas,"2026-06-16 17:05:54"
|
||||||
|
US92338C1036,VLTO,VLTO,Veralto,"2026-06-16 17:05:54"
|
||||||
|
US92343E1029,VRSN,VRSN,Verisign,"2026-06-16 17:05:54"
|
||||||
|
US92556V1061,VTRS,VTRS,Viatris,"2026-06-16 17:05:54"
|
||||||
|
US9256521090,VICI,VICI,"Vici Properties","2026-06-16 17:05:54"
|
||||||
|
US92840M1027,VST,VST,"Vistra Corp.","2026-06-16 17:05:54"
|
||||||
|
US92939U1060,WEC,WEC,"WEC Energy Group","2026-06-16 17:05:54"
|
||||||
|
US9297401088,WAB,WAB,Wabtec,"2026-06-16 17:05:54"
|
||||||
|
US9553061055,WST,WST,"West Pharmaceutical Services","2026-06-16 17:05:54"
|
||||||
|
US9699041011,WSM,WSM,"Williams-Sonoma, Inc.","2026-06-16 17:05:54"
|
||||||
|
US98138H1014,WDAY,WDAY,"Workday, Inc.","2026-06-16 17:05:54"
|
||||||
|
US9831341071,WYNN,WYNN,"Wynn Resorts","2026-06-16 17:05:54"
|
||||||
|
US98419M1009,XYL,XYL,"Xylem Inc.","2026-06-16 17:05:54"
|
||||||
|
US98978V1035,ZTS,ZTS,Zoetis,"2026-06-16 17:05:54"
|
||||||
|
US2787681061,SATS,SATS,"EchoStar Corporation","2026-06-16 16:35:23"
|
||||||
|
US7458671010,PHM,PHM,"PulteGroup Inc.","2026-06-16 16:30:09"
|
||||||
|
US67066G1040,NVDA,NVDA,"Nvidia Corp","2026-06-16 16:28:51"
|
||||||
|
US25809K1051,DASH,DASH,"Dash (DoorDash) Inc. Class A","2026-06-16 16:18:37"
|
||||||
|
US11135F1012,AVGO,AVGO,"Broadcom Inc.","2026-06-16 16:17:39"
|
||||||
|
US2786421030,EBAY,EBAY,"EBay Inc.","2026-06-16 16:16:40"
|
||||||
|
US29444U7000,EQIX,EQIX,"Equinix Inc.","2026-06-16 16:15:41"
|
||||||
|
CH0114405324,GRMN,GRMN,"Garmin Ltd.","2026-06-16 16:14:40"
|
||||||
|
US3755581036,GILD,GILD,"Gilead Sciences Inc.","2026-06-16 16:13:38"
|
||||||
|
US00724F1012,ADBE,ADBE,"Adobe Inc.","2026-06-16 16:12:31"
|
||||||
|
US45337C1027,INCY,INCY,"Incyte Corp.","2026-06-16 16:11:14"
|
||||||
|
BMG611881019,LBTYA,LBTYA,"Liberty Global plc Class A","2026-06-16 16:09:50"
|
||||||
|
US5312297550,FWONK,FWONK,"Liberty Media Corp. Formula One","2026-06-16 16:05:55"
|
||||||
|
US58155Q1031,MCK,MCK,"McKesson Corp.","2026-06-16 16:04:40"
|
||||||
|
US8318652091,AOS,AOS,"Smith (A.O.) Corp.","2026-06-16 16:02:06"
|
||||||
|
US8552441094,SBUX,SBUX,"Starbucks Corp.","2026-06-16 15:59:41"
|
||||||
|
US02079K3059,GOOGL,GOOGL,"Alphabet Inc. Class A","2026-06-16 15:54:59"
|
||||||
|
US98389B1008,XEL,XEL,"Xcel Energy Inc.","2026-06-16 15:40:07"
|
||||||
|
US0079031078,AMD,AMD,"Advanced Micro Devices Inc.","2026-06-16 15:39:17"
|
||||||
|
US0138721065,AA,AA,"Aligned Technology (Altera)","2026-06-16 15:39:17"
|
||||||
|
US02079K1079,GOOG,GOOG,"Alphabet Inc. Class C","2026-06-16 15:39:17"
|
||||||
|
US0258161092,AXP,AXP,"American Express Co","2026-06-16 15:39:17"
|
||||||
|
US0311621009,AMGN,AMGN,"Amgen Inc.","2026-06-16 15:39:17"
|
||||||
|
US0378331005,AAPL,AAPL,"Apple Inc.","2026-06-16 15:39:17"
|
||||||
|
US0970231058,BA,BA,"Boeing Co","2026-06-16 15:39:17"
|
||||||
|
US1266501006,CVS,CVS,"Cisco Systems Inc.","2026-06-16 15:39:17"
|
||||||
|
US1431301027,KMX,KMX,"Caterpillar Inc.","2026-06-16 15:39:17"
|
||||||
|
US1667641005,CVX,CVX,"Chevron Corp.","2026-06-16 15:39:17"
|
||||||
|
US1912161007,KO,KO,"Coca-Cola Co","2026-06-16 15:39:17"
|
||||||
|
US1924461023,CTSH,CTSH,"Cognizant Technology Solutions","2026-06-16 15:39:17"
|
||||||
|
US20030N1019,CMCSA,CMCSA,"Comcast Corp. Class A","2026-06-16 15:39:17"
|
||||||
|
US2058871029,CAG,CAG,"Conagra Brands Inc.","2026-06-16 15:39:17"
|
||||||
|
US2193501051,GLW,GLW,"Constellation Energy Corp.","2026-06-16 15:39:17"
|
||||||
|
US22160K1051,COST,COST,"Costco Wholesale Corp.","2026-06-16 15:39:17"
|
||||||
|
US22822V1017,CCI,CCI,"Crown Castle Inc.","2026-06-16 15:39:17"
|
||||||
|
US2358511028,DHR,DHR,"Danaher Corp.","2026-06-16 15:39:17"
|
||||||
|
US2566771059,DG,DG,"Dollar Tree Inc.","2026-06-16 15:39:17"
|
||||||
|
US2605571031,DOW,DOW,"Dow Inc.","2026-06-16 15:39:17"
|
||||||
|
US30212P3038,EXPE,EXPE,"Fastenal Co.","2026-06-16 15:39:17"
|
||||||
|
US30303M1027,META,META,"Meta Platforms Inc. Class A","2026-06-16 15:39:17"
|
||||||
|
US31620M1062,FIS,FIS,"Fifth Third Bancorp","2026-06-16 15:39:17"
|
||||||
|
US31847R1023,FAF,FAF,"First Solar Inc.","2026-06-16 15:39:17"
|
||||||
|
US3377381088,FISV,FISV,"Fiserv Inc.","2026-06-16 15:39:17"
|
||||||
|
US3696041033,GE,GE,"General Electric Co","2026-06-16 15:39:17"
|
||||||
|
US4180561072,HAS,HAS,"Hasbro Inc.","2026-06-16 15:39:17"
|
||||||
|
US4385161066,HON,HON,"Honeywell International Inc.","2026-06-16 15:39:17"
|
||||||
|
US45167R1041,IEX,IEX,"Idexx Laboratories Inc.","2026-06-16 15:39:17"
|
||||||
|
US4523081093,ITW,ITW,"Illumina Inc.","2026-06-16 15:39:17"
|
||||||
|
US4581401001,INTC,INTC,"Intel Corp.","2026-06-16 15:39:17"
|
||||||
|
US4612021034,INTU,INTU,"Intuitive Surgical Inc.","2026-06-16 15:39:17"
|
||||||
|
US4781601046,JNJ,JNJ,"Johnson & Johnson","2026-06-16 15:39:17"
|
||||||
|
US48123V1026,ZD,ZD,"Keurig Dr Pepper Inc.","2026-06-16 15:39:17"
|
||||||
|
US4824801009,KLAC,KLAC,"KLA Corp.","2026-06-16 15:39:17"
|
||||||
|
US48251W1045,KKR,KKR,"Lam Research Corp.","2026-06-16 15:39:17"
|
||||||
|
US5007541064,KHC,KHC,"Kraft Heinz Co.","2026-06-16 15:39:17"
|
||||||
|
US5324571083,LLY,LLY,"Lilly (Eli) & Co","2026-06-16 15:39:17"
|
||||||
|
US5486611073,LOW,LOW,"Lululemon Athletica Inc.","2026-06-16 15:39:17"
|
||||||
|
US56585A1025,MPC,MPC,"Marriott International Class A","2026-06-16 15:39:17"
|
||||||
|
US5801351017,MCD,MCD,"McDonald's Corp.","2026-06-16 15:39:17"
|
||||||
|
US58933Y1055,MRK,MRK,"Merck & Co. Inc.","2026-06-16 15:39:17"
|
||||||
|
US5949181045,MSFT,MSFT,"Microsoft Corp.","2026-06-16 15:39:17"
|
||||||
|
US5951121038,MU,MU,"Micron Technology Inc.","2026-06-16 15:39:17"
|
||||||
|
US6092071058,MDLZ,MDLZ,"Mondelez International Inc.","2026-06-16 15:39:17"
|
||||||
|
US62944T1051,NVR,NVR,"Netease Inc. ADR","2026-06-16 15:39:17"
|
||||||
|
US6516391066,NEM,NEM,"Newcom Group (Newmont)","2026-06-16 15:39:17"
|
||||||
|
US65339F1012,NEE,NEE,"NextEra Energy Inc.","2026-06-16 15:39:17"
|
||||||
|
US6541061031,NKE,NKE,"Nike Inc. Class B","2026-06-16 15:39:17"
|
||||||
|
US68389X1054,ORCL,ORCL,"O'Reilly Automotive Inc.","2026-06-16 15:39:17"
|
||||||
|
US6935061076,PPG,PPG,"Paccar Inc.","2026-06-16 15:39:17"
|
||||||
|
US70450Y1038,PYPL,PYPL,"PayPal Holdings Inc.","2026-06-16 15:39:17"
|
||||||
|
US7134481081,PEP,PEP,"PepsiCo Inc.","2026-06-16 15:39:17"
|
||||||
|
US7170811035,PFE,PFE,"Pfizer Inc.","2026-06-16 15:39:17"
|
||||||
|
US74251V1026,PFG,PFG,"Prudential Financial Inc.","2026-06-16 15:39:17"
|
||||||
|
US7475251036,QCOM,QCOM,"Qualcomm Inc.","2026-06-16 15:39:17"
|
||||||
|
US7561091049,O,O,"Realty Income Corp.","2026-06-16 15:39:17"
|
||||||
|
US78409V1044,SPGI,SPGI,"S&P Global Inc.","2026-06-16 15:39:17"
|
||||||
|
US8636671013,SYK,SYK,"Stryker Corp.","2026-06-16 15:39:17"
|
||||||
|
US8679141031,STI,STI,"Sunrun Inc.","2026-06-16 15:39:17"
|
||||||
|
US8718291078,SYY,SYY,"Sysco Corp.","2026-06-16 15:39:17"
|
||||||
|
US8725901040,TMUS,TMUS,"T-Mobile US Inc.","2026-06-16 15:39:17"
|
||||||
|
US87612E1064,TGT,TGT,"Target Corp.","2026-06-16 15:39:17"
|
||||||
|
US88160R1014,TSLA,TSLA,"Tesla Inc.","2026-06-16 15:39:17"
|
||||||
|
US8825081040,TXN,TXN,"Texas Instruments Inc.","2026-06-16 15:39:17"
|
||||||
|
US8923561067,TSCO,TSCO,"Tractor Supply Co.","2026-06-16 15:39:17"
|
||||||
|
US9113121068,UPS,UPS,"United Parcel Service Class B","2026-06-16 15:39:17"
|
||||||
|
US91324P1021,UNH,UNH,"UnitedHealth Group Inc.","2026-06-16 15:39:17"
|
||||||
|
US92343V1044,VZ,VZ,"Verisign Inc.","2026-06-16 15:39:17"
|
||||||
|
US92345Y1064,VRSK,VRSK,"Verisk Analytics Inc. Class A","2026-06-16 15:39:17"
|
||||||
|
US92532F1003,VRTX,VRTX,"Vertex Pharmaceuticals Inc.","2026-06-16 15:39:17"
|
||||||
|
US92826C8394,V,V,"Visa Inc. Class A","2026-06-16 15:39:17"
|
||||||
|
US9311421039,WMT,WMT,"Walmart Inc.","2026-06-16 15:39:17"
|
||||||
|
US94106L1098,WM,WM,"Waste Management Inc.","2026-06-16 15:39:17"
|
||||||
|
US9497461015,WFC,WFC,"Wells Fargo & Co.","2026-06-16 15:39:17"
|
||||||
|
US95040Q1040,WELL,WELL,"Western Digital Corp.","2026-06-16 15:39:17"
|
||||||
|
US9884981013,YUM,YUM,"Yum! Brands Inc.","2026-06-16 15:39:17"
|
||||||
|
US98956P1021,ZBH,ZBH,"Zebra Technologies Corp. Class A","2026-06-16 15:39:17"
|
||||||
|
US98980L1017,ZM,ZM,"Zoom Video Communications","2026-06-16 15:39:17"
|
||||||
|
ES0105563003,ANE,ANE.MC,"Acciona Energía","2026-06-16 15:17:14"
|
||||||
|
ES0105025003,MRL,MRL.MC,"Merlin Properties","2026-06-16 15:14:37"
|
||||||
|
ES0105027009,LOG,LOG.MC,Logista,"2026-06-16 15:14:37"
|
||||||
|
ES0105046009,AENA,AENA.MC,Aena,"2026-06-16 15:14:37"
|
||||||
|
ES0105066007,CLNX,CLNX.MC,"Cellnex Telecom","2026-06-16 15:14:37"
|
||||||
|
ES0105777017,PUIG,PUIG.MC,"Puig Brands","2026-06-16 15:14:37"
|
||||||
|
ES0109067019,AMS,AMS.MC,"Amadeus IT Group","2026-06-16 15:14:37"
|
||||||
|
ES0113211835,BBVA,BBVA.MC,BBVA,"2026-06-16 15:14:37"
|
||||||
|
ES0113679I37,BKT,BKT.MC,Bankinter,"2026-06-16 15:14:37"
|
||||||
|
ES0113860A34,SAB,SAB.MC,"Banco Sabadell","2026-06-16 15:14:37"
|
||||||
|
ES0113900J37,SAN,SAN.MC,"Banco Santander","2026-06-16 15:14:37"
|
||||||
|
ES0116870314,NTGY,NTGY.MC,"Naturgy Energy Group","2026-06-16 15:14:37"
|
||||||
|
ES0118594417,IDR,IDR.MC,"Indra Sistemas","2026-06-16 15:14:37"
|
||||||
|
ES0124244E34,MAP,MAP.MC,Mapfre,"2026-06-16 15:14:37"
|
||||||
|
ES0125220311,ANA,ANA.MC,Acciona,"2026-06-16 15:14:37"
|
||||||
|
ES0130670112,ELE,ELE.MC,Endesa,"2026-06-16 15:14:37"
|
||||||
|
ES0130960018,ENG,ENG.MC,Enagás,"2026-06-16 15:14:37"
|
||||||
|
ES0132105018,ACX,ACX.MC,Acerinox,"2026-06-16 15:14:37"
|
||||||
|
ES0137650018,FDR,FDR.MC,Fluidra,"2026-06-16 15:14:37"
|
||||||
|
ES0140609019,CABK,CABK.MC,CaixaBank,"2026-06-16 15:14:37"
|
||||||
|
ES0144580Y14,IBE,IBE.MC,Iberdrola,"2026-06-16 15:14:37"
|
||||||
|
ES0148396007,ITX,ITX.MC,Inditex,"2026-06-16 15:14:37"
|
||||||
|
ES0157261019,ROVI,ROVI.MC,"Laboratorios Farmacéuticos Rovi","2026-06-16 15:14:37"
|
||||||
|
ES0165386014,SLR,SLR.MC,"Solaria Energía","2026-06-16 15:14:37"
|
||||||
|
ES0167050915,ACS,ACS.MC,ACS,"2026-06-16 15:14:37"
|
||||||
|
ES0171996087,GRF,GRF.MC,Grifols,"2026-06-16 15:14:37"
|
||||||
|
ES0173093024,RED,RED.MC,Redeia,"2026-06-16 15:14:37"
|
||||||
|
ES0173516115,REP,REP.MC,Repsol,"2026-06-16 15:14:37"
|
||||||
|
ES0178430E18,TEF,TEF.MC,Telefónica,"2026-06-16 15:14:37"
|
||||||
|
ES0180907000,UNI,UNI.MC,"Unicaja Banco","2026-06-16 15:14:37"
|
||||||
|
ES0182870214,SCYR,SCYR.MC,Sacyr,"2026-06-16 15:14:37"
|
||||||
|
ES0184262212,VIS,VIS.MC,Viscofan,"2026-06-16 15:14:37"
|
||||||
|
LU1598757687,MT,MT.AS,ArcelorMittal,"2026-06-16 15:14:37"
|
||||||
|
NL0015001FS8,FER,FER.MC,Ferrovial,"2026-06-16 15:14:37"
|
||||||
|
FR0013447729,VRLA,VRLA.PA,VERALLIA,"2026-06-16 14:40:56"
|
||||||
|
BE0003470755,SOLB,SOLB.BR,SOLVAY,"2026-06-16 14:39:36"
|
||||||
|
FR0000031577,VIRP,VIRP.PA,VIRBAC,"2026-06-16 14:39:36"
|
||||||
|
FR0000031775,VCT,VCT.PA,VICAT,"2026-06-16 14:39:36"
|
||||||
|
FR0000039299,BOL,BOL.PA,BOLLORE,"2026-06-16 14:39:36"
|
||||||
|
FR0000044448,NEX,NEX.PA,NEXANS,"2026-06-16 14:39:36"
|
||||||
|
FR0000045072,ACA,ACA.PA,"CREDIT AGRICOLE","2026-06-16 14:39:36"
|
||||||
|
FR0000050353,FII,FII.PA,LISI,"2026-06-16 14:39:36"
|
||||||
|
FR0000050809,SOP,SOP.PA,"SOPRA STERIA GROUP","2026-06-16 14:39:36"
|
||||||
|
FR0000051807,TEP,TEP.PA,TELEPERFORMANCE,"2026-06-16 14:39:36"
|
||||||
|
FR0000052292,RMS,RMS.PA,"HERMES INTL","2026-06-16 14:39:36"
|
||||||
|
FR0000053225,MMT,MMT.PA,"METROPOLE TV","2026-06-16 14:39:36"
|
||||||
|
FR0000054470,UBI,UBI.PA,"UBISOFT ENTERTAIN","2026-06-16 14:39:36"
|
||||||
|
FR0000054900,TFI,TFI.PA,TF1,"2026-06-16 14:39:36"
|
||||||
|
FR0000062671,EXA,EXA.PA,"EXAIL TECHNOLOGIES","2026-06-16 14:39:36"
|
||||||
|
FR0000064578,COV,COV.PA,COVIVIO,"2026-06-16 14:39:36"
|
||||||
|
FR0000071946,ATE,ATE.PA,ALTEN,"2026-06-16 14:39:36"
|
||||||
|
FR0000073272,SAF,SAF.PA,SAFRAN,"2026-06-16 14:39:36"
|
||||||
|
FR0000077919,DEC,DEC.PA,JCDECAUX,"2026-06-16 14:39:36"
|
||||||
|
FR0000120073,AI,AI.PA,"AIR LIQUIDE","2026-06-16 14:39:36"
|
||||||
|
FR0000120172,CA,CA.PA,CARREFOUR,"2026-06-16 14:39:36"
|
||||||
|
FR0000120271,TTE,TTE.PA,TOTALENERGIES,"2026-06-16 14:39:36"
|
||||||
|
FR0000120321,OR,OR.PA,L'OREAL,"2026-06-16 14:39:36"
|
||||||
|
FR0000120404,AC,AC.PA,ACCOR,"2026-06-16 14:39:36"
|
||||||
|
FR0000120503,EN,EN.PA,BOUYGUES,"2026-06-16 14:39:36"
|
||||||
|
FR0000120578,SAN,SAN.PA,SANOFI,"2026-06-16 14:39:36"
|
||||||
|
FR0000120628,CS,CS.PA,AXA,"2026-06-16 14:39:36"
|
||||||
|
FR0000120644,BN,BN.PA,DANONE,"2026-06-16 14:39:36"
|
||||||
|
FR0000120693,RI,RI.PA,"PERNOD RICARD","2026-06-16 14:39:36"
|
||||||
|
FR0000120859,NK,NK.PA,IMERYS,"2026-06-16 14:39:36"
|
||||||
|
FR0000120966,BB,BB.PA,BIC,"2026-06-16 14:39:36"
|
||||||
|
FR0000121014,MC,MC.PA,LVMH,"2026-06-16 14:39:36"
|
||||||
|
FR0000121121,RF,RF.PA,EURAZEO,"2026-06-16 14:39:36"
|
||||||
|
FR0000121147,FRVIA,FRVIA.PA,FORVIA,"2026-06-16 14:39:36"
|
||||||
|
FR0000121204,MF,MF.PA,WENDEL,"2026-06-16 14:39:36"
|
||||||
|
FR0000121220,SW,SW.PA,SODEXO,"2026-06-16 14:39:36"
|
||||||
|
FR0000121329,HO,HO.PA,THALES,"2026-06-16 14:39:36"
|
||||||
|
FR0000121485,KER,KER.PA,KERING,"2026-06-16 14:39:36"
|
||||||
|
FR0000121667,EL,EL.PA,ESSILORLUXOTTICA,"2026-06-16 14:39:36"
|
||||||
|
FR0000121709,SK,SK.PA,S.E.B.,"2026-06-16 14:39:36"
|
||||||
|
FR0000121964,LI,LI.PA,KLEPIERRE,"2026-06-16 14:39:36"
|
||||||
|
FR0000121972,SU,SU.PA,"SCHNEIDER ELECTRIC","2026-06-16 14:39:36"
|
||||||
|
FR0000124141,VIE,VIE.PA,"VEOLIA ENVIRON.","2026-06-16 14:39:36"
|
||||||
|
FR0000124570,OPM,OPM.PA,OPMOBILITY,"2026-06-16 14:39:36"
|
||||||
|
FR0000125007,SGO,SGO.PA,"SAINT GOBAIN","2026-06-16 14:39:36"
|
||||||
|
FR0000125338,CAP,CAP.PA,CAPGEMINI,"2026-06-16 14:39:36"
|
||||||
|
FR0000125486,DG,DG.PA,VINCI,"2026-06-16 14:39:36"
|
||||||
|
FR0000127771,VIV,VIV.PA,"VIVENDI SE","2026-06-16 14:39:36"
|
||||||
|
FR0000130395,RCO,RCO.PA,"REMY COINTREAU","2026-06-16 14:39:36"
|
||||||
|
FR0000130452,FGR,FGR.PA,EIFFAGE,"2026-06-16 14:39:36"
|
||||||
|
FR0000130577,PUB,PUB.PA,"PUBLICIS GROUPE SA","2026-06-16 14:39:36"
|
||||||
|
FR0000130809,GLE,GLE.PA,"SOCIETE GENERALE","2026-06-16 14:39:36"
|
||||||
|
FR0000131104,BNP,BNP.PA,"BNP PARIBAS ACT.A","2026-06-16 14:39:36"
|
||||||
|
FR0000131757,ERA,ERA.PA,ERAMET,"2026-06-16 14:39:36"
|
||||||
|
FR0000131906,RNO,RNO.PA,RENAULT,"2026-06-16 14:39:36"
|
||||||
|
FR0000133308,ORA,ORA.PA,ORANGE,"2026-06-16 14:39:36"
|
||||||
|
FR0004024222,ITP,ITP.PA,INTERPARFUMS,"2026-06-16 14:39:36"
|
||||||
|
FR0004056851,VLA,VLA.PA,VALNEVA,"2026-06-16 14:39:36"
|
||||||
|
FR0004065605,FR0004065605,FR0004065605.SG,MEDINCELL,"2026-06-16 14:39:36"
|
||||||
|
FR0004125920,AMUN,AMUN.PA,AMUNDI,"2026-06-16 14:39:36"
|
||||||
|
FR0005691656,TRI,TRI.PA,TRIGANO,"2026-06-16 14:39:36"
|
||||||
|
FR0006174348,BVI,BVI.PA,"BUREAU VERITAS","2026-06-16 14:39:36"
|
||||||
|
FR0010040865,GFC,GFC.PA,GECINA,"2026-06-16 14:39:36"
|
||||||
|
FR0010112524,NXI,NXI.PA,NEXITY,"2026-06-16 14:39:36"
|
||||||
|
FR0010208488,ENGI,ENGI.PA,ENGIE,"2026-06-16 14:39:36"
|
||||||
|
FR0010220475,ALO,ALO.PA,ALSTOM,"2026-06-16 14:39:36"
|
||||||
|
FR0010221234,ETL,ETL.PA,"EUTELSAT COMMUNIC.","2026-06-16 14:39:36"
|
||||||
|
FR0010241638,MERY,MERY.PA,MERCIALYS,"2026-06-16 14:39:36"
|
||||||
|
FR0010259150,IPN,IPN.PA,IPSEN,"2026-06-16 14:39:36"
|
||||||
|
FR0010282822,VU,VU.PA,Vusion,"2026-06-16 14:39:36"
|
||||||
|
FR0010307819,LR,LR.PA,LEGRAND,"2026-06-16 14:39:36"
|
||||||
|
FR0010313833,AKE,AKE.PA,ARKEMA,"2026-06-16 14:39:36"
|
||||||
|
FR0010340141,ADP,ADP.PA,ADP,"2026-06-16 14:39:36"
|
||||||
|
FR0010386334,CLARI,CLARI.PA,CLARIANE,"2026-06-16 14:39:36"
|
||||||
|
FR0010411983,SCR,SCR.PA,"SCOR SE","2026-06-16 14:39:36"
|
||||||
|
FR0010417345,DBV,DBV.PA,"DBV TECHNOLOGIES","2026-06-16 14:39:36"
|
||||||
|
FR0010451203,RXL,RXL.PA,REXEL,"2026-06-16 14:39:36"
|
||||||
|
FR0010481960,ARG,ARG.PA,ARGAN,"2026-06-16 14:39:36"
|
||||||
|
FR0010533075,GET,GET.PA,"GETLINK SE","2026-06-16 14:39:36"
|
||||||
|
FR0010667147,COFA,COFA.PA,COFACE,"2026-06-16 14:39:36"
|
||||||
|
FR0010828137,CARM,CARM.PA,CARMILA,"2026-06-16 14:39:36"
|
||||||
|
FR0010908533,EDEN,EDEN.PA,EDENRED,"2026-06-16 14:39:36"
|
||||||
|
FR0010929125,IDL,IDL.PA,"ID LOGISTICS GROUP","2026-06-16 14:39:36"
|
||||||
|
FR0011341205,NANO,NANO.PA,NANOBIOTIX,"2026-06-16 14:39:36"
|
||||||
|
FR0011726835,GTT,GTT.PA,GTT,"2026-06-16 14:39:36"
|
||||||
|
FR0011950732,ELIOR,ELIOR.PA,"ELIOR GROUP","2026-06-16 14:39:36"
|
||||||
|
FR0012333284,ABVX,ABVX.PA,ABIVAX,"2026-06-16 14:39:36"
|
||||||
|
FR0012435121,ELIS,ELIS.PA,ELIS,"2026-06-16 14:39:36"
|
||||||
|
FR0012757854,SPIE,SPIE.PA,SPIE,"2026-06-16 14:39:36"
|
||||||
|
FR0013154002,DIM,DIM.PA,"SARTORIUS STED BIO","2026-06-16 14:39:36"
|
||||||
|
FR0013176526,FR,FR.PA,VALEO,"2026-06-16 14:39:36"
|
||||||
|
FR0013227113,SOI,SOI.PA,SOITEC,"2026-06-16 14:39:36"
|
||||||
|
FR0013258662,AYV,AYV.PA,AYVENS,"2026-06-16 14:39:36"
|
||||||
|
FR0013269123,RUI,RUI.PA,RUBIS,"2026-06-16 14:39:36"
|
||||||
|
FR0013280286,BIM,BIM.PA,BIOMERIEUX,"2026-06-16 14:39:36"
|
||||||
|
FR0013326246,URW,URW.PA,UNIBAIL-RODAMCO-WE,"2026-06-16 14:39:36"
|
||||||
|
FR0013451333,FDJU,FDJU.PA,"FDJ UNITED","2026-06-16 14:39:36"
|
||||||
|
FR0013506730,VK,VK.PA,VALLOUREC,"2026-06-16 14:39:36"
|
||||||
|
FR0014000MR3,ERF,ERF.PA,"EUROFINS SCIENT.","2026-06-16 14:39:36"
|
||||||
|
FR0014003TT8,DSY,DSY.PA,"DASSAULT SYSTEMES","2026-06-16 14:39:36"
|
||||||
|
FR0014004L86,AM,AM.PA,"DASSAULT AVIATION","2026-06-16 14:39:36"
|
||||||
|
FR001400AJ45,ML,ML.PA,MICHELIN,"2026-06-16 14:39:36"
|
||||||
|
FR001400J770,AF,AF.PA,"AIR FRANCE -KLM","2026-06-16 14:39:36"
|
||||||
|
FR001400NLM4,EMEIS,EMEIS.PA,EMEIS,"2026-06-16 14:39:36"
|
||||||
|
FR001400PVN6,VIRI,VIRI.PA,VIRIDIEN,"2026-06-16 14:39:36"
|
||||||
|
FR001400Q9V2,EXENS,EXENS.PA,EXOSENS,"2026-06-16 14:39:36"
|
||||||
|
FR001400X2S4,ATO,ATO.PA,ATOS,"2026-06-16 14:39:36"
|
||||||
|
FR00140182K6,WLN,WLN.PA,WORLDLINE,"2026-06-16 14:39:36"
|
||||||
|
LU0088087324,SESG,SESG.PA,SES,"2026-06-16 14:39:36"
|
||||||
|
LU0569974404,APAM,APAM.AS,APERAM,"2026-06-16 14:39:36"
|
||||||
|
NL0000226223,STMPA,STMPA.PA,STMICROELECTRONICS,"2026-06-16 14:39:36"
|
||||||
|
NL0000235190,AIR,AIR.PA,AIRBUS,"2026-06-16 14:39:36"
|
||||||
|
NL0006294274,ENX,ENX.PA,EURONEXT,"2026-06-16 14:39:36"
|
||||||
|
NL0014559478,TE,TE.PA,"TECHNIP ENERGIES","2026-06-16 14:39:36"
|
||||||
|
NL00150001Q9,STLAM,STLAM.PA,"STELLANTIS NV","2026-06-16 14:39:36"
|
||||||
|
NL0015001W49,PLX,PLX.PA,PLUXEE,"2026-06-16 14:39:36"
|
||||||
|
+135
@@ -0,0 +1,135 @@
|
|||||||
|
/* 404 page specific styles - Dark glitch / data terminal theme */
|
||||||
|
|
||||||
|
body.page-404 {
|
||||||
|
background: radial-gradient(circle at top, rgba(13, 117, 255, 0.12), transparent 32%),
|
||||||
|
linear-gradient(180deg, #06080f 0%, #050611 100%);
|
||||||
|
color: #e4f0ff;
|
||||||
|
font-family: 'Inter', 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-shell {
|
||||||
|
min-height: calc(100vh - 84px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-card {
|
||||||
|
width: min(900px, 100%);
|
||||||
|
padding: 48px 40px;
|
||||||
|
border-radius: 28px;
|
||||||
|
background: rgba(4, 8, 16, 0.94);
|
||||||
|
border: 1px solid rgba(88, 152, 255, 0.18);
|
||||||
|
box-shadow: 0 26px 80px rgba(0, 0, 0, 0.45);
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-card::before,
|
||||||
|
.error-card::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-card::before {
|
||||||
|
background: linear-gradient(90deg, rgba(255, 255, 255, 0.04), transparent 40%, rgba(255, 255, 255, 0.04));
|
||||||
|
transform: skewX(-12deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-card::after {
|
||||||
|
background-image: radial-gradient(circle at 10% 20%, rgba(3, 155, 255, 0.18), transparent 22%),
|
||||||
|
radial-gradient(circle at 80% 80%, rgba(63, 185, 255, 0.12), transparent 20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-headline {
|
||||||
|
margin: 0 0 16px;
|
||||||
|
font-size: clamp(3rem, 5vw, 6rem);
|
||||||
|
letter-spacing: -0.08em;
|
||||||
|
line-height: 0.9;
|
||||||
|
color: #7df0ff;
|
||||||
|
text-shadow: 0 0 18px rgba(125, 240, 255, 0.28);
|
||||||
|
animation: glowPulse 2.5s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-subtitle {
|
||||||
|
margin: 0 0 24px;
|
||||||
|
color: #b8d3ff;
|
||||||
|
font-size: 1.05rem;
|
||||||
|
line-height: 1.8;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
max-width: 720px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-chip {
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
border: 1px solid rgba(34, 126, 255, 0.18);
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 10px 18px;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: #c4d6ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-return {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 14px 26px;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid rgba(125, 240, 255, 0.5);
|
||||||
|
background: rgba(26, 34, 60, 0.95);
|
||||||
|
color: #e5f4ff;
|
||||||
|
font-size: 0.98rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-decoration: none;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
box-shadow: 0 0 18px rgba(46, 213, 255, 0.12);
|
||||||
|
transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-return:hover,
|
||||||
|
.button-return:focus-visible {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
background: rgba(14, 24, 42, 0.98);
|
||||||
|
box-shadow: 0 0 28px rgba(45, 210, 255, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes glowPulse {
|
||||||
|
0% {
|
||||||
|
text-shadow: 0 0 18px rgba(125, 240, 255, 0.28), 0 0 40px rgba(125, 240, 255, 0.18);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
text-shadow: 0 0 24px rgba(125, 240, 255, 0.55), 0 0 64px rgba(125, 240, 255, 0.25);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.error-card {
|
||||||
|
padding: 32px 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-headline {
|
||||||
|
font-size: clamp(2.4rem, 10vw, 4rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-actions {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
+492
@@ -0,0 +1,492 @@
|
|||||||
|
/* Actions page specific styles - Dark Mode financial UI */
|
||||||
|
|
||||||
|
body.actions-page {
|
||||||
|
--actions-header-height: 76px;
|
||||||
|
--actions-titlebar-height: 80px;
|
||||||
|
--actions-form-height: 220px;
|
||||||
|
--actions-footer-height: 64px;
|
||||||
|
--actions-gap: 10px;
|
||||||
|
background: #070a12;
|
||||||
|
color: #edf2ff;
|
||||||
|
font-family: 'Inter', 'Segoe UI', Arial, sans-serif;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.actions-page header.header {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1003;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-header {
|
||||||
|
position: fixed;
|
||||||
|
top: var(--actions-header-height);
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1002;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
background: rgba(7, 10, 18, 0.98);
|
||||||
|
border-bottom: 1px solid rgba(84, 138, 255, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.actions-page main.main-content {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
min-height: 0;
|
||||||
|
padding-top: calc(var(--actions-header-height) + var(--actions-titlebar-height) + var(--actions-form-height) + var(--actions-gap));
|
||||||
|
padding-bottom: calc(var(--actions-footer-height) + 20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.actions-page .footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1002;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#formulaire-creation {
|
||||||
|
position: fixed;
|
||||||
|
top: calc(var(--actions-header-height) + var(--actions-titlebar-height));
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1001;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.32);
|
||||||
|
background: rgba(7, 10, 18, 0.98);
|
||||||
|
}
|
||||||
|
|
||||||
|
#formulaire-creation .actions-panel {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: min(1200px, 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
width: min(1200px, 100%);
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table-wrapper {
|
||||||
|
height: calc(100vh - var(--actions-header-height) - var(--actions-form-height) - var(--actions-footer-height) - 40px);
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-shell {
|
||||||
|
width: 100%;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-height: 0;
|
||||||
|
padding: 0 20px 28px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-container {
|
||||||
|
width: min(1200px, 100%);
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-height: 0;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table-wrapper {
|
||||||
|
overflow-x: auto;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-card:last-child {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table-wrapper {
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-header .actions-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: clamp(1.8rem, 2.5vw, 2.8rem);
|
||||||
|
letter-spacing: -0.04em;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-header .action-button {
|
||||||
|
width: auto;
|
||||||
|
min-width: 170px;
|
||||||
|
max-width: 260px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-subtitle {
|
||||||
|
color: #94a7d6;
|
||||||
|
margin: 4px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-card,
|
||||||
|
.actions-panel {
|
||||||
|
background: rgba(12, 18, 34, 0.96);
|
||||||
|
border: 1px solid rgba(84, 138, 255, 0.18);
|
||||||
|
border-radius: 24px;
|
||||||
|
box-shadow: 0 24px 70px rgba(0, 0, 0, 0.22);
|
||||||
|
padding: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-panel {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 18px;
|
||||||
|
transition: border-color 0.25s ease, box-shadow 0.25s ease, background 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-panel.edit-mode {
|
||||||
|
border-color: rgba(120, 211, 141, 0.35);
|
||||||
|
box-shadow: 0 28px 90px rgba(46, 160, 95, 0.18);
|
||||||
|
background: rgba(18, 42, 22, 0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-panel label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
color: #d3e1ff;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-panel input,
|
||||||
|
.actions-panel select {
|
||||||
|
background: rgba(15, 22, 41, 0.98);
|
||||||
|
border: 1px solid rgba(96, 156, 255, 0.18);
|
||||||
|
border-radius: 14px;
|
||||||
|
color: #edf2ff;
|
||||||
|
padding: 14px 16px;
|
||||||
|
font-size: 1rem;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-panel input:focus,
|
||||||
|
.actions-panel select:focus {
|
||||||
|
border-color: rgba(89, 151, 255, 0.65);
|
||||||
|
box-shadow: 0 0 0 4px rgba(64, 126, 255, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-panel-footer {
|
||||||
|
margin-top: 12px !important;
|
||||||
|
display: grid;
|
||||||
|
grid-auto-flow: column;
|
||||||
|
justify-content: end;
|
||||||
|
gap: 12px;
|
||||||
|
grid-auto-columns: minmax(140px, max-content);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action,
|
||||||
|
.actions-panel-footer button {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 190px;
|
||||||
|
min-width: 120px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 46px;
|
||||||
|
padding: 0 18px;
|
||||||
|
border-radius: 999px;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease, opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-panel-footer button:hover,
|
||||||
|
.btn-action:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-panel-footer button:disabled,
|
||||||
|
.btn-action:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action:focus-visible {
|
||||||
|
outline: 3px solid rgba(94, 154, 255, 0.45);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
border: 1px solid rgba(94, 154, 255, 0.35);
|
||||||
|
background: linear-gradient(135deg, rgba(72, 124, 255, 0.18), rgba(26, 50, 103, 0.95));
|
||||||
|
color: #f7fbff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action.update-button,
|
||||||
|
.btn-primary.update-button {
|
||||||
|
border-color: rgba(96, 204, 129, 0.35);
|
||||||
|
background: linear-gradient(135deg, rgba(86, 221, 146, 0.18), rgba(50, 90, 72, 0.95));
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-cancel {
|
||||||
|
background: rgba(56, 66, 86, 0.95);
|
||||||
|
border: 1px solid rgba(99, 110, 133, 0.32);
|
||||||
|
color: #d7e6ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-edit-button {
|
||||||
|
border-color: rgba(99, 110, 133, 0.32);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table-wrapper {
|
||||||
|
overflow-x: auto;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
min-width: 720px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table th,
|
||||||
|
.actions-table td {
|
||||||
|
padding: 12px 14px;
|
||||||
|
border-bottom: 1px solid rgba(93, 142, 218, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table th {
|
||||||
|
text-align: left;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: #c7d4f3;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table td {
|
||||||
|
color: #e2ecff;
|
||||||
|
font-size: 0.96rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table th:nth-child(5),
|
||||||
|
.actions-table td:nth-child(5) {
|
||||||
|
min-width: 180px;
|
||||||
|
max-width: 220px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table td:nth-child(5) {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table td .readonly-value {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table td .edit-field {
|
||||||
|
display: none;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table tr.editing .readonly-value {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table tr.editing .edit-field {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-backdrop {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table tbody tr:hover {
|
||||||
|
background: rgba(102, 145, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-action-button,
|
||||||
|
.action-button,
|
||||||
|
.cancel-edit-button,
|
||||||
|
.actions-submit {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 41px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 999px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease, opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-action-button {
|
||||||
|
height: 38px;
|
||||||
|
min-height: 38px;
|
||||||
|
padding: 0 16px;
|
||||||
|
border: 1px solid rgba(94, 154, 255, 0.35);
|
||||||
|
background: rgba(22, 45, 96, 0.95);
|
||||||
|
color: #f7fbff;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button,
|
||||||
|
.cancel-edit-button {
|
||||||
|
padding: 8px 14px;
|
||||||
|
border: 1px solid rgba(100, 159, 255, 0.22);
|
||||||
|
background: rgba(24, 34, 62, 0.98);
|
||||||
|
color: #d7e6ff;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-action-button:hover,
|
||||||
|
.action-button:hover,
|
||||||
|
.cancel-edit-button:hover,
|
||||||
|
.actions-submit:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
background: rgba(72, 122, 255, 0.16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-form-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 25% 12.5% 12.5% 50%;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-form-row label {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-isin {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-ticker,
|
||||||
|
.field-yahoo {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-company {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.action-form-row {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.action-form-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-error,
|
||||||
|
#action-form-feedback {
|
||||||
|
color: #ff7c93;
|
||||||
|
font-size: 0.92rem;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-backdrop {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
background: rgba(4, 8, 20, 0.8);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-panel {
|
||||||
|
width: min(520px, calc(100% - 40px));
|
||||||
|
background: rgba(10, 14, 28, 0.98);
|
||||||
|
border: 1px solid rgba(92, 156, 255, 0.22);
|
||||||
|
border-radius: 24px;
|
||||||
|
padding: 28px;
|
||||||
|
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-panel h2 {
|
||||||
|
margin: 0 0 16px;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
color: #eaf4ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-copy {
|
||||||
|
margin: 0 0 24px;
|
||||||
|
color: #b8c9ff;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-panel .action-button,
|
||||||
|
.modal-panel .actions-submit {
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.actions-panel {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-form-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.actions-card,
|
||||||
|
.actions-panel {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-table th,
|
||||||
|
.actions-table td {
|
||||||
|
padding: 12px 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
body.comptegf-page {
|
||||||
|
--comptegf-header-height: 76px;
|
||||||
|
--comptegf-titlebar-height: 80px;
|
||||||
|
--comptegf-form-height: 260px;
|
||||||
|
--comptegf-footer-height: 64px;
|
||||||
|
background: #070a12;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-page {
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-shell {
|
||||||
|
width: 100%;
|
||||||
|
padding: 1rem;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-button {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
color: #fff;
|
||||||
|
background: var(--accent-color);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-button:hover {
|
||||||
|
background: #1d4ed8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-panel,
|
||||||
|
.comptegf-card {
|
||||||
|
background: rgba(12, 18, 34, 0.96);
|
||||||
|
border: 1px solid rgba(84, 138, 255, 0.18);
|
||||||
|
border-radius: 1rem;
|
||||||
|
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.18);
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-form-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-form-row label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
color: #d3e1ff;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-form-row input {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 2.25rem;
|
||||||
|
padding: 0.65rem 0.85rem;
|
||||||
|
border: 1px solid rgba(96, 156, 255, 0.18);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
background: rgba(15, 22, 41, 0.98);
|
||||||
|
font-size: 0.97rem;
|
||||||
|
color: #edf2ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-form-row input:focus {
|
||||||
|
border-color: rgba(89, 151, 255, 0.65);
|
||||||
|
outline: none;
|
||||||
|
box-shadow: 0 0 0 4px rgba(64, 126, 255, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-panel-footer {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action {
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
padding: 0.6rem 1rem;
|
||||||
|
min-height: 38px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
transition: transform 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
background-color: rgba(37, 99, 235, 0.16);
|
||||||
|
color: #edf2ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: #2563eb;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-edit {
|
||||||
|
background-color: #2563eb;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-cancel {
|
||||||
|
background-color: rgba(255, 255, 255, 0.08);
|
||||||
|
color: #edf2ff;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table-wrapper {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
min-width: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table th,
|
||||||
|
.comptegf-table td {
|
||||||
|
padding: 0.75rem 0.85rem;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table th {
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table tr.totals-row th,
|
||||||
|
.comptegf-table tr.totals-row td {
|
||||||
|
background: rgba(37, 99, 235, 0.12);
|
||||||
|
color: #edf2ff;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table tr.totals-row th.totals-label {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table td.numeric-cell {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table .totals-value {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table tbody td:nth-child(1) {
|
||||||
|
width: 17%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table tbody td:nth-child(2) {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table tbody td:nth-child(3),
|
||||||
|
.comptegf-table tbody td:nth-child(4),
|
||||||
|
.comptegf-table tbody td:nth-child(5) {
|
||||||
|
width: 11%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table tr:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-error {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
background: rgba(248, 113, 113, 0.12);
|
||||||
|
color: #f8c0c0;
|
||||||
|
border: 1px solid rgba(248, 113, 113, 0.24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-notice {
|
||||||
|
padding: 1rem 1.25rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.comptegf-page .form-error,
|
||||||
|
body.comptegf-page .action-notice {
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border-color: rgba(255, 255, 255, 0.1);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-success {
|
||||||
|
background: rgba(16, 185, 129, 0.14);
|
||||||
|
border: 1px solid rgba(16, 185, 129, 0.24);
|
||||||
|
color: #a7f3d0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-error {
|
||||||
|
background: rgba(248, 113, 113, 0.14);
|
||||||
|
border: 1px solid rgba(248, 113, 113, 0.24);
|
||||||
|
color: #fecaca;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.comptegf-form-row {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.comptegf-form-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
/* Duplicate of compteGF dark styles but for compteJFG */
|
||||||
|
body.comptejfg-page {
|
||||||
|
--comptegf-header-height: 76px;
|
||||||
|
--comptegf-titlebar-height: 80px;
|
||||||
|
--comptegf-form-height: 260px;
|
||||||
|
--comptegf-footer-height: 64px;
|
||||||
|
background: #070a12;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptejfg-page {
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-shell {
|
||||||
|
width: 100%;
|
||||||
|
padding: 1rem;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-button {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
color: #fff;
|
||||||
|
background: var(--accent-color);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-button:hover {
|
||||||
|
background: #1d4ed8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-panel,
|
||||||
|
.comptegf-card {
|
||||||
|
background: rgba(12, 18, 34, 0.96);
|
||||||
|
border: 1px solid rgba(84, 138, 255, 0.18);
|
||||||
|
border-radius: 1rem;
|
||||||
|
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.18);
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-form-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-form-row label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
color: #d3e1ff;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-form-row input {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 2.25rem;
|
||||||
|
padding: 0.65rem 0.85rem;
|
||||||
|
border: 1px solid rgba(96, 156, 255, 0.18);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
background: rgba(15, 22, 41, 0.98);
|
||||||
|
font-size: 0.97rem;
|
||||||
|
color: #edf2ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-form-row input:focus {
|
||||||
|
border-color: rgba(89, 151, 255, 0.65);
|
||||||
|
outline: none;
|
||||||
|
box-shadow: 0 0 0 4px rgba(64, 126, 255, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-panel-footer {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action {
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
padding: 0.6rem 1rem;
|
||||||
|
min-height: 38px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
transition: transform 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
background-color: rgba(37, 99, 235, 0.16);
|
||||||
|
color: #edf2ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: #2563eb;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-edit {
|
||||||
|
background-color: #2563eb;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-cancel {
|
||||||
|
background-color: rgba(255, 255, 255, 0.08);
|
||||||
|
color: #edf2ff;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table-wrapper {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
min-width: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table th,
|
||||||
|
.comptegf-table td {
|
||||||
|
padding: 0.75rem 0.85rem;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table th {
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table tr.totals-row th,
|
||||||
|
.comptegf-table tr.totals-row td {
|
||||||
|
background: rgba(37, 99, 235, 0.12);
|
||||||
|
color: #edf2ff;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table tr.totals-row th.totals-label {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table td.numeric-cell {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table .totals-value {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table tbody td:nth-child(1) {
|
||||||
|
width: 17%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table tbody td:nth-child(2) {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table tbody td:nth-child(3),
|
||||||
|
.comptegf-table tbody td:nth-child(4),
|
||||||
|
.comptegf-table tbody td:nth-child(5) {
|
||||||
|
width: 11%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-table tr:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-error {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
background: rgba(248, 113, 113, 0.12);
|
||||||
|
color: #f8c0c0;
|
||||||
|
border: 1px solid rgba(248, 113, 113, 0.24);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-notice {
|
||||||
|
padding: 1rem 1.25rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.comptejfg-page .form-error,
|
||||||
|
body.comptejfg-page .action-notice {
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border-color: rgba(255, 255, 255, 0.1);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-success {
|
||||||
|
background: rgba(16, 185, 129, 0.14);
|
||||||
|
border: 1px solid rgba(16, 185, 129, 0.24);
|
||||||
|
color: #a7f3d0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-error {
|
||||||
|
background: rgba(248, 113, 113, 0.14);
|
||||||
|
border: 1px solid rgba(248, 113, 113, 0.24);
|
||||||
|
color: #fecaca;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.comptegf-form-row {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.comptegf-form-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comptegf-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
/* Styles pour la page de synchronisation CSV */
|
||||||
|
|
||||||
|
body.csv-page {
|
||||||
|
background: #08101f;
|
||||||
|
color: #e7eefc;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.csv-shell {
|
||||||
|
min-height: calc(100vh - 120px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 30px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.csv-card {
|
||||||
|
width: min(780px, 100%);
|
||||||
|
background: rgba(12, 18, 32, 0.96);
|
||||||
|
border: 1px solid rgba(113, 153, 255, 0.16);
|
||||||
|
border-radius: 22px;
|
||||||
|
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.28);
|
||||||
|
padding: 32px;
|
||||||
|
display: grid;
|
||||||
|
gap: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.csv-content {
|
||||||
|
display: grid;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.csv-card h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: clamp(1.8rem, 2.5vw, 2.8rem);
|
||||||
|
letter-spacing: -0.04em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.csv-status {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #d3e6ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-ok {
|
||||||
|
color: #c5f0c7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-warning {
|
||||||
|
color: #ffdab3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.csv-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action {
|
||||||
|
border: 1px solid rgba(102, 138, 255, 0.24);
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 12px 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
|
||||||
|
min-width: 110px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-action:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: linear-gradient(135deg, rgba(72, 124, 255, 0.16), rgba(34, 46, 88, 0.98));
|
||||||
|
color: #f7fbff;
|
||||||
|
border-color: rgba(90, 142, 255, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
background: rgba(24, 32, 58, 0.96);
|
||||||
|
color: #d7e6ff;
|
||||||
|
border-color: rgba(118, 143, 190, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.csv-feedback {
|
||||||
|
min-height: 24px;
|
||||||
|
color: #f7b3b3;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.csv-card {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.csv-actions {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
+131
@@ -0,0 +1,131 @@
|
|||||||
|
/* Menu page specific styles - Dark mode modern UI */
|
||||||
|
|
||||||
|
body.menu-page {
|
||||||
|
background: #090b10;
|
||||||
|
color: #e8effa;
|
||||||
|
font-family: Inter, 'Segoe UI', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-shell {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: stretch;
|
||||||
|
padding: 20px 8px 40px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-card {
|
||||||
|
width: min(1080px, 100%);
|
||||||
|
background: rgba(15, 21, 35, 0.98);
|
||||||
|
border: 1px solid rgba(120, 140, 190, 0.18);
|
||||||
|
border-radius: 28px;
|
||||||
|
box-shadow: 0 22px 80px rgba(0, 0, 0, 0.4);
|
||||||
|
backdrop-filter: blur(18px);
|
||||||
|
padding: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-card__header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-card__title {
|
||||||
|
font-size: clamp(1.8rem, 2.5vw, 2.6rem);
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.05;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-card__subtitle {
|
||||||
|
color: #97a3c0;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 22px 24px;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 1px solid rgba(110, 146, 255, 0.2);
|
||||||
|
background: linear-gradient(180deg, rgba(15, 23, 45, 0.95), rgba(18, 24, 42, 0.98));
|
||||||
|
color: #f5f9ff;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
|
||||||
|
min-height: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-button:hover,
|
||||||
|
.menu-button:focus-visible {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
border-color: rgba(91, 132, 255, 0.75);
|
||||||
|
box-shadow: 0 20px 60px rgba(45, 67, 122, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-button__content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-button__title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-button__text {
|
||||||
|
color: #97a3c0;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-button__icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
border-radius: 16px;
|
||||||
|
background: rgba(87, 132, 255, 0.14);
|
||||||
|
color: #7fa2ff;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-note {
|
||||||
|
margin-top: 30px;
|
||||||
|
color: #8090b3;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 860px) {
|
||||||
|
.menu-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-card {
|
||||||
|
padding: 32px 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 520px) {
|
||||||
|
.menu-card {
|
||||||
|
padding: 24px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-button {
|
||||||
|
min-height: 110px;
|
||||||
|
padding: 18px 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
+229
@@ -0,0 +1,229 @@
|
|||||||
|
:root {
|
||||||
|
--ordregf-bg: #13161f;
|
||||||
|
--ordregf-card: #1c2030;
|
||||||
|
--ordregf-border: rgba(255, 255, 255, 0.08);
|
||||||
|
--ordregf-text: #f0f2fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force le plein écran */
|
||||||
|
.ordregf-page {
|
||||||
|
background-color: var(--ordregf-bg);
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ordregf-shell {
|
||||||
|
width: 100%;
|
||||||
|
max-width: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ordregf-card {
|
||||||
|
background: var(--ordregf-card);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tables en pleine largeur */
|
||||||
|
.ordregf-table,
|
||||||
|
.ordregf-detail-table {
|
||||||
|
width: 100% !important;
|
||||||
|
border-collapse: collapse;
|
||||||
|
table-layout: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alignements entêtes */
|
||||||
|
.ordregf-table th,
|
||||||
|
.ordregf-detail-table th {
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ordregf-detail-table th {
|
||||||
|
text-align: center !important;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ordregf-detail-table td {
|
||||||
|
padding: 8px;
|
||||||
|
border-bottom: 1px solid var(--ordregf-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Styles boutons */
|
||||||
|
.ordregf-edit-button {
|
||||||
|
padding: 4px 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Boutons principaux (Créer et Retour) */
|
||||||
|
.ordregf-btn-menu,
|
||||||
|
.ordregf-btn-creer {
|
||||||
|
padding: 10px 24px !important;
|
||||||
|
border-radius: 50px !important;
|
||||||
|
border: none !important;
|
||||||
|
cursor: pointer !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
transition: background 0.3s ease !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bouton Menu (Bleu) */
|
||||||
|
.ordregf-btn-menu {
|
||||||
|
background-color: #1a237e !important;
|
||||||
|
}
|
||||||
|
.ordregf-btn-menu:hover {
|
||||||
|
background-color: #283593 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bouton Créer (Vert) */
|
||||||
|
.ordregf-btn-creer {
|
||||||
|
background-color: #28a745 !important;
|
||||||
|
}
|
||||||
|
.ordregf-btn-creer:hover {
|
||||||
|
background-color: #218838 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Styles lignes */
|
||||||
|
.ordregf-header-style {
|
||||||
|
background: rgba(255, 255, 255, 0.05) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ordregf-header-style td {
|
||||||
|
color: #fff !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
padding: 12px !important;
|
||||||
|
border-bottom: 2px solid rgba(255, 255, 255, 0.1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ordregf-detail-row td {
|
||||||
|
padding: 10px 5px !important;
|
||||||
|
border-bottom: 1px solid var(--ordregf-border);
|
||||||
|
color: #e0e0e0;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ordregf-detail-row:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alignement colonnes numériques */
|
||||||
|
.ordregf-detail-table .text-right {
|
||||||
|
text-align: right !important;
|
||||||
|
padding-right: 15px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Classe commune : force la taille et l'alignement */
|
||||||
|
.ordregf-btn-petit {
|
||||||
|
width: 90px; /* Largeur fixe pour tous les petits boutons */
|
||||||
|
height: 30px; /* Hauteur fixe pour un alignement vertical parfait */
|
||||||
|
padding: 0 10px; /* Padding horizontal */
|
||||||
|
font-size: 0.8em;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: inline-flex; /* Utilise Flexbox pour centrer le texte */
|
||||||
|
align-items: center; /* Centre verticalement */
|
||||||
|
justify-content: center; /* Centre horizontalement */
|
||||||
|
box-sizing: border-box; /* Important : inclut padding/border dans la largeur */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Couleurs spécifiques */
|
||||||
|
.ordregf-btn-creer-petit {
|
||||||
|
background-color: #28a745;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.ordregf-btn-creer-petit:hover {
|
||||||
|
background-color: #218838;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ordregf-btn-modifier-petit {
|
||||||
|
background-color: #1a237e;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.ordregf-btn-modifier-petit:hover {
|
||||||
|
background-color: #283593;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ordregf-modal {
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
background: #1c2030;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.ordregf-modal input {
|
||||||
|
background: #13161f;
|
||||||
|
border: 1px solid #333;
|
||||||
|
color: white;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
.modal-actions {
|
||||||
|
margin-top: 15px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ordregf-master-row {
|
||||||
|
background: linear-gradient(90deg, #001f3f, #004cff) !important;
|
||||||
|
color: #ffffff;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
|
box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************/
|
||||||
|
|
||||||
|
/* 1. On nettoie le body */
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden; /* Empêche le scroll de la page entière */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. On positionne le shell en absolu pour qu'il s'insère entre le header et le footer */
|
||||||
|
.ordregf-shell {
|
||||||
|
position: absolute;
|
||||||
|
top: 80px; /* Hauteur exacte de votre header */
|
||||||
|
bottom: 50px; /* Hauteur exacte de votre footer */
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 10px; /* Un léger espace intérieur pour l'esthétique */
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. La carte occupe l'espace restant */
|
||||||
|
.ordregf-card {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden; /* Important pour que le scroll ne sorte pas de la carte */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. C'est ici que le scroll se passe */
|
||||||
|
.ordregf-table-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto; /* Active le scroll uniquement ici */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Important : reset des marges du tableau qui pourraient le pousser */
|
||||||
|
.ordregf-table {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
+22
-6
@@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
html {
|
html {
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
|
min-height: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -41,6 +43,15 @@ body {
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body > .main-content {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
@@ -147,14 +158,17 @@ body {
|
|||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 2px 20px;
|
padding: 8px 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
line-height: 1.1;
|
line-height: 1.3;
|
||||||
min-height: 28px;
|
min-height: 38px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
background: rgba(18, 24, 42, 0.98);
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-logout {
|
.footer-logout {
|
||||||
@@ -184,11 +198,13 @@ body {
|
|||||||
============================================ */
|
============================================ */
|
||||||
|
|
||||||
.main-content {
|
.main-content {
|
||||||
flex: 1;
|
flex: 1 0 auto;
|
||||||
padding: 40px 20px;
|
min-height: 0;
|
||||||
|
padding: 40px 20px 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-container {
|
.login-container {
|
||||||
|
|||||||
+134
@@ -0,0 +1,134 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const actionForm = document.getElementById('action-form');
|
||||||
|
const actionIsinInput = document.querySelector('input[name="action_isin"]');
|
||||||
|
const isinInput = document.getElementById('action-isin');
|
||||||
|
const tickerInput = document.getElementById('action-ticker');
|
||||||
|
const yahooInput = document.getElementById('action-yahoo_code');
|
||||||
|
const companyInput = document.getElementById('action-company_name');
|
||||||
|
const feedbackMessage = document.getElementById('action-form-feedback');
|
||||||
|
const createButton = document.querySelector('.create-button');
|
||||||
|
const updateButton = document.querySelector('.update-button');
|
||||||
|
const cancelEditButton = document.querySelector('.cancel-edit-button');
|
||||||
|
const actionsPanel = document.querySelector('.actions-panel');
|
||||||
|
const editActionButtons = document.querySelectorAll('.edit-action-button');
|
||||||
|
|
||||||
|
const getExistingActions = () => Array.from(document.querySelectorAll('.action-row')).map((row) => ({
|
||||||
|
isin: row.dataset.isin || '',
|
||||||
|
ticker: row.dataset.ticker || '',
|
||||||
|
yahoo_code: row.dataset.yahoo_code || '',
|
||||||
|
company_name: row.dataset.company_name || '',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const setFeedback = (message) => {
|
||||||
|
if (!feedbackMessage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
feedbackMessage.textContent = message;
|
||||||
|
feedbackMessage.style.display = message ? 'block' : 'none';
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateDuplicateFields = () => {
|
||||||
|
const existingActions = getExistingActions();
|
||||||
|
const currentActionIsin = actionIsinInput.value.trim();
|
||||||
|
const currentIsin = isinInput.value.trim();
|
||||||
|
const currentTicker = tickerInput.value.trim();
|
||||||
|
const currentYahoo = yahooInput.value.trim();
|
||||||
|
|
||||||
|
const duplicateFields = [];
|
||||||
|
|
||||||
|
const isDuplicate = (fieldName, value) => {
|
||||||
|
if (!value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return existingActions.some((entry) => {
|
||||||
|
if (!entry[fieldName]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (currentActionIsin && entry.isin === currentActionIsin) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return entry[fieldName].localeCompare(value, undefined, { sensitivity: 'base' }) === 0;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isDuplicate('isin', currentIsin)) {
|
||||||
|
duplicateFields.push('ISIN');
|
||||||
|
}
|
||||||
|
if (isDuplicate('ticker', currentTicker)) {
|
||||||
|
duplicateFields.push('symbole');
|
||||||
|
}
|
||||||
|
if (isDuplicate('yahoo_code', currentYahoo)) {
|
||||||
|
duplicateFields.push('code Yahoo');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duplicateFields.length > 0) {
|
||||||
|
const joined = duplicateFields.join(', ');
|
||||||
|
setFeedback(`Doublon détecté pour le(s) champ(s) : ${joined}. Veuillez modifier la saisie.`);
|
||||||
|
createButton.disabled = true;
|
||||||
|
updateButton.disabled = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setFeedback('');
|
||||||
|
createButton.disabled = false;
|
||||||
|
updateButton.disabled = false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetFormMode = () => {
|
||||||
|
actionForm.reset();
|
||||||
|
actionIsinInput.value = '';
|
||||||
|
createButton.removeAttribute('disabled');
|
||||||
|
createButton.hidden = false;
|
||||||
|
updateButton.hidden = true;
|
||||||
|
cancelEditButton.hidden = true;
|
||||||
|
isinInput.removeAttribute('readonly');
|
||||||
|
isinInput.removeAttribute('disabled');
|
||||||
|
actionsPanel.classList.remove('edit-mode');
|
||||||
|
setFeedback('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const setEditMode = (row) => {
|
||||||
|
const isin = row.dataset.isin || '';
|
||||||
|
const ticker = row.dataset.ticker || '';
|
||||||
|
const yahooCode = row.dataset.yahoo_code || '';
|
||||||
|
const companyName = row.dataset.company_name || '';
|
||||||
|
|
||||||
|
actionIsinInput.value = isin;
|
||||||
|
isinInput.value = isin;
|
||||||
|
tickerInput.value = ticker;
|
||||||
|
yahooInput.value = yahooCode;
|
||||||
|
companyInput.value = companyName;
|
||||||
|
|
||||||
|
createButton.setAttribute('disabled', 'disabled');
|
||||||
|
createButton.hidden = true;
|
||||||
|
updateButton.hidden = false;
|
||||||
|
cancelEditButton.hidden = false;
|
||||||
|
isinInput.setAttribute('readonly', 'readonly');
|
||||||
|
actionsPanel.classList.add('edit-mode');
|
||||||
|
validateDuplicateFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputChange = () => {
|
||||||
|
validateDuplicateFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
editActionButtons.forEach((button) => {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
const row = button.closest('tr');
|
||||||
|
if (!row) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setEditMode(row);
|
||||||
|
isinInput.focus();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
[isinInput, tickerInput, yahooInput].forEach((input) => {
|
||||||
|
input.addEventListener('input', handleInputChange);
|
||||||
|
});
|
||||||
|
|
||||||
|
cancelEditButton.addEventListener('click', resetFormMode);
|
||||||
|
|
||||||
|
resetFormMode();
|
||||||
|
});
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const compteForm = document.getElementById('comptegf-form');
|
||||||
|
const compteIdInput = document.querySelector('input[name="comptegf_id"]');
|
||||||
|
const dateInput = document.getElementById('comptegf-date_operation');
|
||||||
|
const debitInput = document.getElementById('comptegf-debit');
|
||||||
|
const creditInput = document.getElementById('comptegf-credit');
|
||||||
|
const libelleInput = document.getElementById('comptegf-libelle');
|
||||||
|
const feedbackMessage = document.getElementById('comptegf-form-feedback');
|
||||||
|
const createButton = document.querySelector('.create-button');
|
||||||
|
const updateButton = document.querySelector('.update-button');
|
||||||
|
const cancelEditButton = document.querySelector('.cancel-edit-button');
|
||||||
|
const panel = document.querySelector('.comptegf-panel');
|
||||||
|
const editButtons = document.querySelectorAll('.edit-comptegf-button');
|
||||||
|
|
||||||
|
const setFeedback = (message) => {
|
||||||
|
if (!feedbackMessage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
feedbackMessage.textContent = message;
|
||||||
|
feedbackMessage.style.display = message ? 'block' : 'none';
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetFormMode = () => {
|
||||||
|
if (!compteForm) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
compteForm.reset();
|
||||||
|
compteIdInput.value = '';
|
||||||
|
createButton.removeAttribute('disabled');
|
||||||
|
createButton.hidden = false;
|
||||||
|
updateButton.hidden = true;
|
||||||
|
cancelEditButton.hidden = true;
|
||||||
|
dateInput.removeAttribute('readonly');
|
||||||
|
setFeedback('');
|
||||||
|
panel.classList.remove('edit-mode');
|
||||||
|
};
|
||||||
|
|
||||||
|
const setEditMode = (row) => {
|
||||||
|
const id = row.dataset.id || '';
|
||||||
|
const dateOperation = row.dataset.date_operation || '';
|
||||||
|
const debit = row.dataset.debit || '0.00';
|
||||||
|
const credit = row.dataset.credit || '0.00';
|
||||||
|
const libelle = row.dataset.libelle || '';
|
||||||
|
|
||||||
|
compteIdInput.value = id;
|
||||||
|
dateInput.value = dateOperation;
|
||||||
|
debitInput.value = debit;
|
||||||
|
creditInput.value = credit;
|
||||||
|
libelleInput.value = libelle;
|
||||||
|
|
||||||
|
createButton.setAttribute('disabled', 'disabled');
|
||||||
|
createButton.hidden = true;
|
||||||
|
updateButton.hidden = false;
|
||||||
|
cancelEditButton.hidden = false;
|
||||||
|
panel.classList.add('edit-mode');
|
||||||
|
setFeedback('Mode édition activé. Modifiez puis enregistrez.');
|
||||||
|
};
|
||||||
|
|
||||||
|
editButtons.forEach((button) => {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
const row = button.closest('tr');
|
||||||
|
if (!row) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setEditMode(row);
|
||||||
|
libelleInput.focus();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
cancelEditButton.addEventListener('click', resetFormMode);
|
||||||
|
resetFormMode();
|
||||||
|
});
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const compteForm = document.getElementById('comptejfg-form');
|
||||||
|
const compteIdInput = document.querySelector('input[name="comptejfg_id"]');
|
||||||
|
const dateInput = document.getElementById('comptejfg-date_operation');
|
||||||
|
const debitInput = document.getElementById('comptejfg-debit');
|
||||||
|
const creditInput = document.getElementById('comptejfg-credit');
|
||||||
|
const libelleInput = document.getElementById('comptejfg-libelle');
|
||||||
|
const feedbackMessage = document.getElementById('comptejfg-form-feedback');
|
||||||
|
const createButton = document.querySelector('.create-button');
|
||||||
|
const updateButton = document.querySelector('.update-button');
|
||||||
|
const cancelEditButton = document.querySelector('.cancel-edit-button');
|
||||||
|
const panel = document.querySelector('.comptegf-panel');
|
||||||
|
const editButtons = document.querySelectorAll('.edit-comptejfg-button');
|
||||||
|
|
||||||
|
const setFeedback = (message) => {
|
||||||
|
if (!feedbackMessage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
feedbackMessage.textContent = message;
|
||||||
|
feedbackMessage.style.display = message ? 'block' : 'none';
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetFormMode = () => {
|
||||||
|
if (!compteForm) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
compteForm.reset();
|
||||||
|
compteIdInput.value = '';
|
||||||
|
createButton.removeAttribute('disabled');
|
||||||
|
createButton.hidden = false;
|
||||||
|
updateButton.hidden = true;
|
||||||
|
cancelEditButton.hidden = true;
|
||||||
|
dateInput.removeAttribute('readonly');
|
||||||
|
setFeedback('');
|
||||||
|
panel.classList.remove('edit-mode');
|
||||||
|
};
|
||||||
|
|
||||||
|
const setEditMode = (row) => {
|
||||||
|
const id = row.dataset.id || '';
|
||||||
|
const dateOperation = row.dataset.date_operation || '';
|
||||||
|
const debit = row.dataset.debit || '0.00';
|
||||||
|
const credit = row.dataset.credit || '0.00';
|
||||||
|
const libelle = row.dataset.libelle || '';
|
||||||
|
|
||||||
|
compteIdInput.value = id;
|
||||||
|
dateInput.value = dateOperation;
|
||||||
|
debitInput.value = debit;
|
||||||
|
creditInput.value = credit;
|
||||||
|
libelleInput.value = libelle;
|
||||||
|
|
||||||
|
createButton.setAttribute('disabled', 'disabled');
|
||||||
|
createButton.hidden = true;
|
||||||
|
updateButton.hidden = false;
|
||||||
|
cancelEditButton.hidden = false;
|
||||||
|
dateInput.setAttribute('readonly', 'readonly');
|
||||||
|
panel.classList.add('edit-mode');
|
||||||
|
setFeedback('Mode édition activé. Modifiez puis enregistrez.');
|
||||||
|
};
|
||||||
|
|
||||||
|
editButtons.forEach((button) => {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
const row = button.closest('tr');
|
||||||
|
if (!row) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setEditMode(row);
|
||||||
|
libelleInput.focus();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
cancelEditButton.addEventListener('click', resetFormMode);
|
||||||
|
resetFormMode();
|
||||||
|
});
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const updateButton = document.getElementById('csv-update-yes');
|
||||||
|
const cancelButton = document.getElementById('csv-update-no');
|
||||||
|
const feedbackElement = document.getElementById('csv-feedback');
|
||||||
|
|
||||||
|
if (!updateButton || !cancelButton || !feedbackElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const setFeedback = (message, isError = false) => {
|
||||||
|
feedbackElement.textContent = message;
|
||||||
|
feedbackElement.style.color = isError ? '#ffb3b3' : '#b8f2b8';
|
||||||
|
};
|
||||||
|
|
||||||
|
updateButton.addEventListener('click', async () => {
|
||||||
|
updateButton.disabled = true;
|
||||||
|
cancelButton.disabled = true;
|
||||||
|
setFeedback('Mise à jour en cours, veuillez patienter...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/php/update_csv.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (!response.ok || !result.success) {
|
||||||
|
const message = result.message || 'Échec de la mise à jour CSV.';
|
||||||
|
setFeedback(message, true);
|
||||||
|
updateButton.disabled = false;
|
||||||
|
cancelButton.disabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setFeedback(result.message || 'CSV mis à jour avec succès.', false);
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = '/php/csv.php';
|
||||||
|
}, 1200);
|
||||||
|
} catch (error) {
|
||||||
|
setFeedback('Erreur réseau lors de la mise à jour CSV.', true);
|
||||||
|
updateButton.disabled = false;
|
||||||
|
cancelButton.disabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cancelButton.addEventListener('click', () => {
|
||||||
|
window.location.href = '/php/menu.php';
|
||||||
|
});
|
||||||
|
});
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const menuButtons = document.querySelectorAll('.menu-button[data-target]');
|
||||||
|
|
||||||
|
menuButtons.forEach((button) => {
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
const target = button.getAttribute('data-target');
|
||||||
|
if (target) {
|
||||||
|
window.location.href = target;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
+121
@@ -0,0 +1,121 @@
|
|||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
// --- 1. GESTION DES MODALS ET FORMULAIRES ---
|
||||||
|
|
||||||
|
// Modal Créer Ordre
|
||||||
|
const modalCreerOrdre = document.getElementById("modalCreerOrdre");
|
||||||
|
const btnCreer = document.querySelector(".ordregf-btn-creer");
|
||||||
|
|
||||||
|
if (modalCreerOrdre && btnCreer) {
|
||||||
|
btnCreer.addEventListener("click", () => modalCreerOrdre.showModal());
|
||||||
|
|
||||||
|
document.getElementById("btnAnnuler")?.addEventListener("click", () => {
|
||||||
|
document.getElementById("formCreerOrdre").reset();
|
||||||
|
modalCreerOrdre.close();
|
||||||
|
document.getElementById("btnValider").disabled = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recherche Action
|
||||||
|
const btnRechercher = document.getElementById("btnRechercher");
|
||||||
|
btnRechercher?.addEventListener("click", async () => {
|
||||||
|
const isin = document.getElementById("isinRecherche").value;
|
||||||
|
if (!isin) return alert("Veuillez entrer un code ISIN");
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`/php/api_rechercher_action.php?isin=${encodeURIComponent(isin)}`,
|
||||||
|
);
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.success) {
|
||||||
|
document.getElementById("Nom").value = data.company_name;
|
||||||
|
document.getElementById("ticker").value = data.ticker;
|
||||||
|
document.getElementById("code_yahoo").value = data.yahoo_code;
|
||||||
|
document.getElementById("btnValider").disabled = false;
|
||||||
|
} else {
|
||||||
|
alert("Action non trouvée");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Enregistrement Ordre
|
||||||
|
document
|
||||||
|
.getElementById("formCreerOrdre")
|
||||||
|
?.addEventListener("submit", async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
// FormData récupère automatiquement tous les champs ayant un attribut "name"
|
||||||
|
const formData = new FormData(e.target);
|
||||||
|
|
||||||
|
const response = await fetch("/php/api_enregistrer_ordre.php", {
|
||||||
|
method: "POST",
|
||||||
|
body: formData,
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.success) {
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
alert(
|
||||||
|
"Erreur lors de l'enregistrement : " +
|
||||||
|
(result.message || "Erreur inconnue"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Enregistrement Detail
|
||||||
|
document
|
||||||
|
.getElementById("formCreerDetail")
|
||||||
|
?.addEventListener("submit", async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const response = await fetch("/php/api_enregistrer_detail.php", {
|
||||||
|
method: "POST",
|
||||||
|
body: new FormData(e.target),
|
||||||
|
});
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.success) location.reload();
|
||||||
|
else
|
||||||
|
alert(
|
||||||
|
"Erreur lors de l'enregistrement du détail : " +
|
||||||
|
(result.message || ""),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- 2. GESTION MODIFICATION (DÉLÉGATION D'ÉVÉNEMENT) ---
|
||||||
|
|
||||||
|
document.addEventListener("click", (e) => {
|
||||||
|
const button = e.target.closest(".ordregf-btn-modifier-petit");
|
||||||
|
if (button) {
|
||||||
|
const detail = JSON.parse(button.getAttribute("data-detail"));
|
||||||
|
const modal = document.getElementById("modalModifierDetail");
|
||||||
|
if (modal) {
|
||||||
|
document.getElementById("edit_id").value = detail.Id;
|
||||||
|
document.getElementById("edit_Id_entete").value = detail.Id_entete;
|
||||||
|
document.getElementById("edit_date").value = detail.Date_op;
|
||||||
|
document.getElementById("edit_quantite").value = detail.Quantite;
|
||||||
|
document.getElementById("edit_prix").value = detail.Prix_brut;
|
||||||
|
document.getElementById("edit_frais_broker").value =
|
||||||
|
detail.Frais_brocker || 0;
|
||||||
|
document.getElementById("edit_frais_etat").value =
|
||||||
|
detail.Frais_etat || 0;
|
||||||
|
document.getElementById("edit_frais_autre").value =
|
||||||
|
detail.Frais_autre || 0;
|
||||||
|
document.getElementById("edit_ordre").value = detail.Ordre;
|
||||||
|
modal.showModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Soumission Modification
|
||||||
|
const formModif = document.getElementById("formModifierDetail");
|
||||||
|
formModif?.addEventListener("submit", async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const response = await fetch("/php/api_modifier_detail.php", {
|
||||||
|
method: "POST",
|
||||||
|
body: new FormData(e.target),
|
||||||
|
});
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.success) {
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
alert("Erreur : " + result.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
+24
-10
@@ -1,16 +1,30 @@
|
|||||||
<?php
|
<?php
|
||||||
// On envoie explicitement le code d'erreur 404 au navigateur
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
|
|
||||||
require_once('header.php');
|
$pageStylesheets = ['/css/404.css'];
|
||||||
|
$bodyClass = 'page-404';
|
||||||
|
|
||||||
|
require_once __DIR__ . '/header.php';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div style="text-align: center; padding: 50px; color: white;">
|
<section class="error-shell">
|
||||||
<h1>Erreur 404</h1>
|
<article class="error-card">
|
||||||
<p>Désolé, la page que vous recherchez est introuvable.</p>
|
<h1 class="error-headline">404</h1>
|
||||||
<a href="/index.php" style="color: #007bff;">Retour à l'accueil</a>
|
<p class="error-subtitle">La transaction est introuvable. Le cours de cette page a chuté et le marché n’en veut plus.</p>
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php
|
<div class="error-meta">
|
||||||
require_once('footer.php');
|
<span class="meta-chip">Route : /404</span>
|
||||||
?>
|
<span class="meta-chip">Status : Page non cotée</span>
|
||||||
|
<span class="meta-chip">Session : <?= htmlspecialchars((string) ($_SESSION['user_id'] ?? 'invité'), ENT_QUOTES, 'UTF-8') ?></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="error-actions">
|
||||||
|
<a href="/index.php" class="button-return">Retour à la base</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/footer.php'; ?>
|
||||||
+159
@@ -0,0 +1,159 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require_once __DIR__ . '/session.php';
|
||||||
|
require_once __DIR__ . '/db.php';
|
||||||
|
|
||||||
|
// Redirection si l'utilisateur n'est pas authentifié.
|
||||||
|
if (empty($_SESSION['user_id'])) {
|
||||||
|
header('Location: ../index.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageStylesheets = ['/css/actions.css'];
|
||||||
|
$bodyClass = 'actions-page';
|
||||||
|
|
||||||
|
$database = new App\Database\Database();
|
||||||
|
$actionsManager = new App\Database\ActionsManager($database);
|
||||||
|
|
||||||
|
// Traitement du formulaire d'ajout d'une nouvelle action.
|
||||||
|
$creationMessage = null;
|
||||||
|
$creationError = null;
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action_create'])) {
|
||||||
|
$newAction = [
|
||||||
|
'isin' => trim($_POST['isin'] ?? ''),
|
||||||
|
'ticker' => trim($_POST['ticker'] ?? ''),
|
||||||
|
'yahoo_code' => trim($_POST['yahoo_code'] ?? ''),
|
||||||
|
'company_name' => trim($_POST['company_name'] ?? ''),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($newAction['isin'] === '' || $newAction['ticker'] === '' || $newAction['company_name'] === '') {
|
||||||
|
$creationError = 'Veuillez remplir tous les champs obligatoires.';
|
||||||
|
} else {
|
||||||
|
if ($actionsManager->createAction($newAction)) {
|
||||||
|
$creationMessage = 'Nouvelle action ajoutée avec succès.';
|
||||||
|
} else {
|
||||||
|
$creationError = 'Impossible d’ajouter l’action, veuillez réessayer.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traitement du formulaire de mise à jour d'une action.
|
||||||
|
$updateMessage = null;
|
||||||
|
$updateError = null;
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action_update'], $_POST['action_isin'])) {
|
||||||
|
$actionIsin = trim($_POST['action_isin']);
|
||||||
|
$updateData = [
|
||||||
|
'ticker' => trim($_POST['ticker'] ?? ''),
|
||||||
|
'yahoo_code' => trim($_POST['yahoo_code'] ?? ''),
|
||||||
|
'company_name' => trim($_POST['company_name'] ?? ''),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($actionIsin === '' || $updateData['ticker'] === '' || $updateData['company_name'] === '') {
|
||||||
|
$updateError = 'Tous les champs requis doivent être remplis pour mettre à jour cette action.';
|
||||||
|
} else {
|
||||||
|
if ($actionsManager->updateAction($actionIsin, $updateData)) {
|
||||||
|
$updateMessage = 'Action mise à jour avec succès.';
|
||||||
|
} else {
|
||||||
|
$updateError = 'Impossible de mettre à jour l’action. Vérifiez les données et réessayez.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$actions = $actionsManager->listActions();
|
||||||
|
|
||||||
|
require_once __DIR__ . '/header.php';
|
||||||
|
?>
|
||||||
|
|
||||||
|
<section class="actions-shell">
|
||||||
|
<div class="actions-container">
|
||||||
|
<div class="actions-header">
|
||||||
|
<h1 class="actions-title">Actions financières</h1>
|
||||||
|
<a href="/php/menu.php" class="action-button">Retour au menu</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($creationMessage): ?>
|
||||||
|
<div class="actions-card action-notice action-success"><?= htmlspecialchars($creationMessage, ENT_QUOTES, 'UTF-8') ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($creationError): ?>
|
||||||
|
<div class="actions-card action-notice action-error"><?= htmlspecialchars($creationError, ENT_QUOTES, 'UTF-8') ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($updateMessage): ?>
|
||||||
|
<div class="actions-card action-notice action-success"><?= htmlspecialchars($updateMessage, ENT_QUOTES, 'UTF-8') ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($updateError): ?>
|
||||||
|
<div class="actions-card action-notice action-error"><?= htmlspecialchars($updateError, ENT_QUOTES, 'UTF-8') ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<section class="actions-panel" id="formulaire-creation">
|
||||||
|
<form id="action-form" method="post" action="" autocomplete="off">
|
||||||
|
<input type="hidden" name="action_isin" value="">
|
||||||
|
<div class="action-form-row">
|
||||||
|
<label class="field-isin">
|
||||||
|
ISIN
|
||||||
|
<input id="action-isin" type="text" name="isin" placeholder="Ex. FR0000123456" required>
|
||||||
|
</label>
|
||||||
|
<label class="field-ticker">
|
||||||
|
Symbole
|
||||||
|
<input id="action-ticker" type="text" name="ticker" placeholder="EXA" required>
|
||||||
|
</label>
|
||||||
|
<label class="field-yahoo">
|
||||||
|
Code Yahoo
|
||||||
|
<input id="action-yahoo_code" type="text" name="yahoo_code" placeholder="EXA.PA" required>
|
||||||
|
</label>
|
||||||
|
<label class="field-company">
|
||||||
|
Société
|
||||||
|
<input id="action-company_name" type="text" name="company_name" placeholder="Société Alpha" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div id="action-form-feedback" class="form-error" aria-live="polite" style="display:none;"></div>
|
||||||
|
<div class="actions-panel-footer">
|
||||||
|
<button type="submit" name="action_create" class="btn-action btn-primary create-button">Créer une action</button>
|
||||||
|
<button type="submit" name="action_update" class="btn-action btn-primary update-button" hidden>Modifier l'action</button>
|
||||||
|
<button type="button" class="btn-action btn-cancel cancel-edit-button" hidden>Annuler</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="actions-card table-container">
|
||||||
|
<div class="actions-table-wrapper">
|
||||||
|
<table class="actions-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ISIN</th>
|
||||||
|
<th>Symbole</th>
|
||||||
|
<th>Code Yahoo</th>
|
||||||
|
<th>Société</th>
|
||||||
|
<th>Mise à jour</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($actions as $action): ?>
|
||||||
|
<tr class="action-row"
|
||||||
|
data-isin="<?= htmlspecialchars((string) $action['isin'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
data-ticker="<?= htmlspecialchars((string) $action['ticker'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
data-yahoo_code="<?= htmlspecialchars((string) $action['yahoo_code'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
data-company_name="<?= htmlspecialchars((string) $action['company_name'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
>
|
||||||
|
<td><?= htmlspecialchars((string) $action['isin'], ENT_QUOTES, 'UTF-8') ?></td>
|
||||||
|
<td><?= htmlspecialchars((string) $action['ticker'], ENT_QUOTES, 'UTF-8') ?></td>
|
||||||
|
<td><?= htmlspecialchars((string) $action['yahoo_code'], ENT_QUOTES, 'UTF-8') ?></td>
|
||||||
|
<td><?= htmlspecialchars((string) $action['company_name'], ENT_QUOTES, 'UTF-8') ?></td>
|
||||||
|
<td><?= htmlspecialchars((string) $action['updated_at'], ENT_QUOTES, 'UTF-8') ?></td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn-action btn-edit edit-action-button">Modifier</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="/js/actions.js" defer></script>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/footer.php'; ?>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/db.php';
|
||||||
|
$db = (new App\Database\Database())->getConnection();
|
||||||
|
|
||||||
|
$stmt = $db->prepare("INSERT INTO ordreGF_pied
|
||||||
|
(Id_entete, Date_op, Quantite, Prix_brut, Frais_brocker, Frais_etat, Frais_autre, Ordre, Type, Etat)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||||
|
|
||||||
|
$success = $stmt->execute([
|
||||||
|
$_POST['Id_entete'],
|
||||||
|
$_POST['Date_op'],
|
||||||
|
$_POST['Quantite'],
|
||||||
|
$_POST['Prix_brut'],
|
||||||
|
$_POST['Frais_brocker'],
|
||||||
|
$_POST['Frais_etat'],
|
||||||
|
$_POST['Frais_autre'],
|
||||||
|
$_POST['Ordre'],
|
||||||
|
$_POST['Type'],
|
||||||
|
$_POST['Etat']
|
||||||
|
]);
|
||||||
|
|
||||||
|
echo json_encode(['success' => $success]);
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
require_once __DIR__ . '/db.php';
|
||||||
|
$db = (new App\Database\Database())->getConnection();
|
||||||
|
$stmt = $db->prepare("INSERT INTO ordreGF (isin, Nom, ticker, code_yahoo) VALUES (?, ?, ?, ?)");
|
||||||
|
$success = $stmt->execute([$_POST['isin'], $_POST['Nom'], $_POST['ticker'], $_POST['code_yahoo']]);
|
||||||
|
|
||||||
|
echo json_encode(['success' => $success]);
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
require_once __DIR__ . '/db.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
try {
|
||||||
|
$db = (new App\Database\Database())->getConnection();
|
||||||
|
|
||||||
|
$sql = "UPDATE ordreGF_pied SET
|
||||||
|
Date_op = :date,
|
||||||
|
Quantite = :qte,
|
||||||
|
Prix_brut = :prix,
|
||||||
|
Frais_brocker = :f_b,
|
||||||
|
Frais_etat = :f_e,
|
||||||
|
Frais_autre = :f_a,
|
||||||
|
Ordre = :ordre
|
||||||
|
WHERE Id = :id";
|
||||||
|
|
||||||
|
$stmt = $db->prepare($sql);
|
||||||
|
$stmt->execute([
|
||||||
|
':date' => $_POST['Date_op'],
|
||||||
|
':qte' => $_POST['Quantite'],
|
||||||
|
':prix' => $_POST['Prix_brut'],
|
||||||
|
':f_b' => $_POST['Frais_brocker'],
|
||||||
|
':f_e' => $_POST['Frais_etat'],
|
||||||
|
':f_a' => $_POST['Frais_autre'],
|
||||||
|
':ordre' => $_POST['Ordre'],
|
||||||
|
':id' => $_POST['id']
|
||||||
|
]);
|
||||||
|
|
||||||
|
echo json_encode(['success' => true]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/db.php';
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$db = (new App\Database\Database())->getConnection();
|
||||||
|
|
||||||
|
// Récupération des données POST
|
||||||
|
$id = $_POST['id'];
|
||||||
|
$nom = $_POST['nom'];
|
||||||
|
$ticker = $_POST['ticker'];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $db->prepare("UPDATE ordres SET nom = ?, ticker = ? WHERE id = ?");
|
||||||
|
$stmt->execute([$nom, $ticker, $id]);
|
||||||
|
|
||||||
|
echo json_encode(['success' => true]);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/db.php';
|
||||||
|
$isin = $_GET['isin'] ?? '';
|
||||||
|
$db = (new App\Database\Database())->getConnection();
|
||||||
|
$stmt = $db->prepare("SELECT * FROM actions WHERE isin = ?");
|
||||||
|
$stmt->execute([$isin]);
|
||||||
|
$action = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
echo json_encode($action ? ['success' => true, ...$action] : ['success' => false]);
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require_once __DIR__ . '/session.php';
|
||||||
|
require_once __DIR__ . '/db.php';
|
||||||
|
|
||||||
|
// Redirection si l'utilisateur n'est pas authentifié.
|
||||||
|
if (empty($_SESSION['user_id'])) {
|
||||||
|
header('Location: ../index.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageStylesheets = ['/css/compteGF.css'];
|
||||||
|
$bodyClass = 'comptegf-page';
|
||||||
|
|
||||||
|
$database = new App\Database\Database();
|
||||||
|
$compteGFManager = new App\Database\CompteGFManager($database);
|
||||||
|
|
||||||
|
$creationMessage = null;
|
||||||
|
$creationError = null;
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['comptegf_create'])) {
|
||||||
|
$newEntry = [
|
||||||
|
'date_operation' => trim($_POST['date_operation'] ?? ''),
|
||||||
|
'debit' => trim($_POST['debit'] ?? '0.00'),
|
||||||
|
'credit' => trim($_POST['credit'] ?? '0.00'),
|
||||||
|
'libelle' => trim($_POST['libelle'] ?? ''),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($newEntry['date_operation'] === '' || $newEntry['libelle'] === '') {
|
||||||
|
$creationError = 'Veuillez remplir la date et le libellé.';
|
||||||
|
} else {
|
||||||
|
if ($compteGFManager->createCompteGF($newEntry)) {
|
||||||
|
$creationMessage = 'Nouvelle écriture ajoutée avec succès.';
|
||||||
|
} else {
|
||||||
|
$creationError = 'Impossible d’ajouter l’écriture, veuillez réessayer.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$updateMessage = null;
|
||||||
|
$updateError = null;
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['comptegf_update'], $_POST['comptegf_id'])) {
|
||||||
|
$entryId = (int) $_POST['comptegf_id'];
|
||||||
|
$updateData = [
|
||||||
|
'date_operation' => trim($_POST['date_operation'] ?? ''),
|
||||||
|
'debit' => trim($_POST['debit'] ?? '0.00'),
|
||||||
|
'credit' => trim($_POST['credit'] ?? '0.00'),
|
||||||
|
'libelle' => trim($_POST['libelle'] ?? ''),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($entryId <= 0 || $updateData['date_operation'] === '' || $updateData['libelle'] === '') {
|
||||||
|
$updateError = 'Tous les champs requis doivent être remplis pour mettre à jour cette écriture.';
|
||||||
|
} else {
|
||||||
|
if ($compteGFManager->updateCompteGF($entryId, $updateData)) {
|
||||||
|
$updateMessage = 'Écriture mise à jour avec succès.';
|
||||||
|
} else {
|
||||||
|
$updateError = 'Impossible de mettre à jour l’écriture. Vérifiez les données et réessayez.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$entries = $compteGFManager->listCompteGF();
|
||||||
|
|
||||||
|
$totalCredit = 0.0;
|
||||||
|
$totalDebit = 0.0;
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$totalCredit += (float) $entry['credit'];
|
||||||
|
$totalDebit += (float) $entry['debit'];
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once __DIR__ . '/header.php';
|
||||||
|
?>
|
||||||
|
|
||||||
|
<section class="comptegf-shell">
|
||||||
|
<div class="comptegf-container">
|
||||||
|
<div class="comptegf-header">
|
||||||
|
<h1 class="comptegf-title">Compte GF</h1>
|
||||||
|
<a href="/php/menu.php" class="comptegf-button">Retour au menu</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($creationMessage): ?>
|
||||||
|
<div class="comptegf-card action-notice action-success"><?= htmlspecialchars($creationMessage, ENT_QUOTES, 'UTF-8') ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($creationError): ?>
|
||||||
|
<div class="comptegf-card action-notice action-error"><?= htmlspecialchars($creationError, ENT_QUOTES, 'UTF-8') ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($updateMessage): ?>
|
||||||
|
<div class="comptegf-card action-notice action-success"><?= htmlspecialchars($updateMessage, ENT_QUOTES, 'UTF-8') ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($updateError): ?>
|
||||||
|
<div class="comptegf-card action-notice action-error"><?= htmlspecialchars($updateError, ENT_QUOTES, 'UTF-8') ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<section class="comptegf-panel" id="formulaire-creation">
|
||||||
|
<form id="comptegf-form" method="post" action="" autocomplete="off">
|
||||||
|
<input type="hidden" name="comptegf_id" value="">
|
||||||
|
<div class="comptegf-form-row">
|
||||||
|
<label class="field-date_operation">
|
||||||
|
Date opération
|
||||||
|
<input id="comptegf-date_operation" type="date" name="date_operation" required>
|
||||||
|
</label>
|
||||||
|
<label class="field-libelle">
|
||||||
|
Libellé
|
||||||
|
<input id="comptegf-libelle" type="text" name="libelle" placeholder="Description" required>
|
||||||
|
</label>
|
||||||
|
<label class="field-credit">
|
||||||
|
Crédit
|
||||||
|
<input id="comptegf-credit" type="number" name="credit" step="0.01" min="0" value="0.00" required>
|
||||||
|
</label>
|
||||||
|
<label class="field-debit">
|
||||||
|
Débit
|
||||||
|
<input id="comptegf-debit" type="number" name="debit" step="0.01" min="0" value="0.00" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div id="comptegf-form-feedback" class="form-error" aria-live="polite" style="display:none;"></div>
|
||||||
|
<div class="comptegf-panel-footer">
|
||||||
|
<button type="submit" name="comptegf_create" class="btn-action btn-primary create-button">Créer une écriture</button>
|
||||||
|
<button type="submit" name="comptegf_update" class="btn-action btn-primary update-button" hidden>Modifier l'écriture</button>
|
||||||
|
<button type="button" class="btn-action btn-cancel cancel-edit-button" hidden>Annuler</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="comptegf-card table-container">
|
||||||
|
<div class="comptegf-table-wrapper">
|
||||||
|
<table class="comptegf-table">
|
||||||
|
<thead>
|
||||||
|
<tr class="totals-row">
|
||||||
|
<th colspan="2" class="totals-label">Totaux :</th>
|
||||||
|
<th class="numeric-cell totals-value"><?= htmlspecialchars(number_format($totalCredit, 2, ',', ' '), ENT_QUOTES, 'UTF-8') ?></th>
|
||||||
|
<th class="numeric-cell totals-value"><?= htmlspecialchars(number_format($totalDebit, 2, ',', ' '), ENT_QUOTES, 'UTF-8') ?></th>
|
||||||
|
<th class="numeric-cell totals-value"><?= htmlspecialchars(number_format($totalCredit - $totalDebit, 2, ',', ' '), ENT_QUOTES, 'UTF-8') ?></th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Date opération</th>
|
||||||
|
<th>Libellé</th>
|
||||||
|
<th>Crédit</th>
|
||||||
|
<th>Débit</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($entries as $entry): ?>
|
||||||
|
<?php
|
||||||
|
$formattedDate = $entry['date_operation'];
|
||||||
|
if (!empty($entry['date_operation'])) {
|
||||||
|
$dateTime = DateTime::createFromFormat('Y-m-d', $entry['date_operation']);
|
||||||
|
if ($dateTime !== false) {
|
||||||
|
$formattedDate = $dateTime->format('d/m/Y');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<tr class="comptegf-row"
|
||||||
|
data-id="<?= htmlspecialchars((string) $entry['id'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
data-date_operation="<?= htmlspecialchars((string) $entry['date_operation'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
data-debit="<?= htmlspecialchars((string) $entry['debit'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
data-credit="<?= htmlspecialchars((string) $entry['credit'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
data-libelle="<?= htmlspecialchars((string) $entry['libelle'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
>
|
||||||
|
<td><?= htmlspecialchars((string) $formattedDate, ENT_QUOTES, 'UTF-8') ?></td>
|
||||||
|
<td><?= htmlspecialchars((string) $entry['libelle'], ENT_QUOTES, 'UTF-8') ?></td>
|
||||||
|
<td class="numeric-cell"><?= htmlspecialchars((string) $entry['credit'], ENT_QUOTES, 'UTF-8') ?></td>
|
||||||
|
<td class="numeric-cell"><?= htmlspecialchars((string) $entry['debit'], ENT_QUOTES, 'UTF-8') ?></td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn-action btn-edit edit-comptegf-button">Modifier</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="/js/compteGF.js" defer></script>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/footer.php';
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require_once __DIR__ . '/session.php';
|
||||||
|
require_once __DIR__ . '/db.php';
|
||||||
|
|
||||||
|
// Redirection si l'utilisateur n'est pas authentifié.
|
||||||
|
if (empty($_SESSION['user_id'])) {
|
||||||
|
header('Location: ../index.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageStylesheets = ['/css/compteJFG.css'];
|
||||||
|
$bodyClass = 'comptejfg-page';
|
||||||
|
|
||||||
|
$database = new App\Database\Database();
|
||||||
|
$compteJFGManager = new App\Database\CompteJFGManager($database);
|
||||||
|
|
||||||
|
$creationMessage = null;
|
||||||
|
$creationError = null;
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['comptejfg_create'])) {
|
||||||
|
$newEntry = [
|
||||||
|
'date_operation' => trim($_POST['date_operation'] ?? ''),
|
||||||
|
'debit' => trim($_POST['debit'] ?? '0.00'),
|
||||||
|
'credit' => trim($_POST['credit'] ?? '0.00'),
|
||||||
|
'libelle' => trim($_POST['libelle'] ?? ''),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($newEntry['date_operation'] === '' || $newEntry['libelle'] === '') {
|
||||||
|
$creationError = 'Veuillez remplir la date et le libellé.';
|
||||||
|
} else {
|
||||||
|
if ($compteJFGManager->createCompteJFG($newEntry)) {
|
||||||
|
$creationMessage = 'Nouvelle écriture ajoutée avec succès.';
|
||||||
|
} else {
|
||||||
|
$creationError = 'Impossible d’ajouter l’écriture, veuillez réessayer.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$updateMessage = null;
|
||||||
|
$updateError = null;
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['comptejfg_update'], $_POST['comptejfg_id'])) {
|
||||||
|
$entryId = (int) $_POST['comptejfg_id'];
|
||||||
|
$updateData = [
|
||||||
|
'date_operation' => trim($_POST['date_operation'] ?? ''),
|
||||||
|
'debit' => trim($_POST['debit'] ?? '0.00'),
|
||||||
|
'credit' => trim($_POST['credit'] ?? '0.00'),
|
||||||
|
'libelle' => trim($_POST['libelle'] ?? ''),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($entryId <= 0 || $updateData['date_operation'] === '' || $updateData['libelle'] === '') {
|
||||||
|
$updateError = 'Tous les champs requis doivent être remplis pour mettre à jour cette écriture.';
|
||||||
|
} else {
|
||||||
|
if ($compteJFGManager->updateCompteJFG($entryId, $updateData)) {
|
||||||
|
$updateMessage = 'Écriture mise à jour avec succès.';
|
||||||
|
} else {
|
||||||
|
$updateError = 'Impossible de mettre à jour l’écriture. Vérifiez les données et réessayez.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$entries = $compteJFGManager->listCompteJFG();
|
||||||
|
|
||||||
|
$totalCredit = 0.0;
|
||||||
|
$totalDebit = 0.0;
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$totalCredit += (float) $entry['credit'];
|
||||||
|
$totalDebit += (float) $entry['debit'];
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once __DIR__ . '/header.php';
|
||||||
|
?>
|
||||||
|
|
||||||
|
<section class="comptegf-shell">
|
||||||
|
<div class="comptegf-container">
|
||||||
|
<div class="comptegf-header">
|
||||||
|
<h1 class="comptegf-title">Compte JFG</h1>
|
||||||
|
<a href="/php/menu.php" class="comptegf-button">Retour au menu</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($creationMessage): ?>
|
||||||
|
<div class="comptegf-card action-notice action-success"><?= htmlspecialchars($creationMessage, ENT_QUOTES, 'UTF-8') ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($creationError): ?>
|
||||||
|
<div class="comptegf-card action-notice action-error"><?= htmlspecialchars($creationError, ENT_QUOTES, 'UTF-8') ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($updateMessage): ?>
|
||||||
|
<div class="comptegf-card action-notice action-success"><?= htmlspecialchars($updateMessage, ENT_QUOTES, 'UTF-8') ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($updateError): ?>
|
||||||
|
<div class="comptegf-card action-notice action-error"><?= htmlspecialchars($updateError, ENT_QUOTES, 'UTF-8') ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<section class="comptegf-panel" id="formulaire-creation">
|
||||||
|
<form id="comptejfg-form" method="post" action="" autocomplete="off">
|
||||||
|
<input type="hidden" name="comptejfg_id" value="">
|
||||||
|
<div class="comptegf-form-row">
|
||||||
|
<label class="field-date_operation">
|
||||||
|
Date opération
|
||||||
|
<input id="comptejfg-date_operation" type="date" name="date_operation" required>
|
||||||
|
</label>
|
||||||
|
<label class="field-libelle">
|
||||||
|
Libellé
|
||||||
|
<input id="comptejfg-libelle" type="text" name="libelle" placeholder="Description" required>
|
||||||
|
</label>
|
||||||
|
<label class="field-credit">
|
||||||
|
Crédit
|
||||||
|
<input id="comptejfg-credit" type="number" name="credit" step="0.01" min="0" value="0.00" required>
|
||||||
|
</label>
|
||||||
|
<label class="field-debit">
|
||||||
|
Débit
|
||||||
|
<input id="comptejfg-debit" type="number" name="debit" step="0.01" min="0" value="0.00" required>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div id="comptejfg-form-feedback" class="form-error" aria-live="polite" style="display:none;"></div>
|
||||||
|
<div class="comptegf-panel-footer">
|
||||||
|
<button type="submit" name="comptejfg_create" class="btn-action btn-primary create-button">Créer une écriture</button>
|
||||||
|
<button type="submit" name="comptejfg_update" class="btn-action btn-primary update-button" hidden>Modifier l'écriture</button>
|
||||||
|
<button type="button" class="btn-action btn-cancel cancel-edit-button" hidden>Annuler</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="comptegf-card table-container">
|
||||||
|
<div class="comptegf-table-wrapper">
|
||||||
|
<table class="comptegf-table">
|
||||||
|
<thead>
|
||||||
|
<tr class="totals-row">
|
||||||
|
<th colspan="2" class="totals-label">Totaux :</th>
|
||||||
|
<th class="numeric-cell totals-value"><?= htmlspecialchars(number_format($totalCredit, 2, ',', ' '), ENT_QUOTES, 'UTF-8') ?></th>
|
||||||
|
<th class="numeric-cell totals-value"><?= htmlspecialchars(number_format($totalDebit, 2, ',', ' '), ENT_QUOTES, 'UTF-8') ?></th>
|
||||||
|
<th class="numeric-cell totals-value"><?= htmlspecialchars(number_format($totalCredit - $totalDebit, 2, ',', ' '), ENT_QUOTES, 'UTF-8') ?></th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Date opération</th>
|
||||||
|
<th>Libellé</th>
|
||||||
|
<th>Crédit</th>
|
||||||
|
<th>Débit</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($entries as $entry): ?>
|
||||||
|
<?php
|
||||||
|
$formattedDate = $entry['date_operation'];
|
||||||
|
if (!empty($entry['date_operation'])) {
|
||||||
|
$dateTime = DateTime::createFromFormat('Y-m-d', $entry['date_operation']);
|
||||||
|
if ($dateTime !== false) {
|
||||||
|
$formattedDate = $dateTime->format('d/m/Y');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<tr class="comptegf-row"
|
||||||
|
data-id="<?= htmlspecialchars((string) $entry['id'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
data-date_operation="<?= htmlspecialchars((string) $entry['date_operation'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
data-debit="<?= htmlspecialchars((string) $entry['debit'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
data-credit="<?= htmlspecialchars((string) $entry['credit'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
data-libelle="<?= htmlspecialchars((string) $entry['libelle'], ENT_QUOTES, 'UTF-8') ?>"
|
||||||
|
>
|
||||||
|
<td><?= htmlspecialchars((string) $formattedDate, ENT_QUOTES, 'UTF-8') ?></td>
|
||||||
|
<td><?= htmlspecialchars((string) $entry['libelle'], ENT_QUOTES, 'UTF-8') ?></td>
|
||||||
|
<td class="numeric-cell"><?= htmlspecialchars((string) $entry['credit'], ENT_QUOTES, 'UTF-8') ?></td>
|
||||||
|
<td class="numeric-cell"><?= htmlspecialchars((string) $entry['debit'], ENT_QUOTES, 'UTF-8') ?></td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn-action btn-edit edit-comptejfg-button">Modifier</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="/js/compteJFG.js" defer></script>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/footer.php';
|
||||||
+125
@@ -0,0 +1,125 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require_once __DIR__ . '/session.php';
|
||||||
|
require_once __DIR__ . '/db.php';
|
||||||
|
|
||||||
|
use App\Database\Database;
|
||||||
|
use App\Database\ActionsManager;
|
||||||
|
|
||||||
|
if (empty($_SESSION['user_id'])) {
|
||||||
|
header('Location: ../index.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageStylesheets = ['/css/csv.css'];
|
||||||
|
$pageScripts = ['/js/csv.js'];
|
||||||
|
$bodyClass = 'csv-page';
|
||||||
|
|
||||||
|
$database = new Database();
|
||||||
|
$actionsManager = new ActionsManager($database);
|
||||||
|
|
||||||
|
$csvFilePath = __DIR__ . '/../assets/csv/actions.csv';
|
||||||
|
$csvRecords = [];
|
||||||
|
$csvReadError = null;
|
||||||
|
$csvExists = is_readable($csvFilePath);
|
||||||
|
|
||||||
|
if ($csvExists) {
|
||||||
|
$handle = fopen($csvFilePath, 'r');
|
||||||
|
if ($handle === false) {
|
||||||
|
$csvExists = false;
|
||||||
|
$csvReadError = 'Impossible de lire le fichier CSV.';
|
||||||
|
} else {
|
||||||
|
$header = fgetcsv($handle);
|
||||||
|
while (($row = fgetcsv($handle)) !== false) {
|
||||||
|
if (count($row) < 4) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$isin = trim((string) ($row[0] ?? ''));
|
||||||
|
if ($isin === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$csvRecords[$isin] = [
|
||||||
|
'ticker' => trim((string) ($row[1] ?? '')),
|
||||||
|
'yahoo_code' => trim((string) ($row[2] ?? '')),
|
||||||
|
'company_name' => trim((string) ($row[3] ?? '')),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$actions = $actionsManager->listActions();
|
||||||
|
$differences = [];
|
||||||
|
|
||||||
|
foreach ($actions as $action) {
|
||||||
|
$isin = trim((string) ($action['isin'] ?? ''));
|
||||||
|
if ($isin === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
'ticker' => trim((string) ($action['ticker'] ?? '')),
|
||||||
|
'yahoo_code' => trim((string) ($action['yahoo_code'] ?? '')),
|
||||||
|
'company_name' => trim((string) ($action['company_name'] ?? '')),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!isset($csvRecords[$isin])) {
|
||||||
|
$differences[] = ['isin' => $isin, 'reason' => 'absent'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$csvRow = $csvRecords[$isin];
|
||||||
|
foreach ($expected as $field => $value) {
|
||||||
|
if ($csvRow[$field] !== $value) {
|
||||||
|
$differences[] = ['isin' => $isin, 'reason' => $field];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$csvReady = $csvExists && empty($differences);
|
||||||
|
|
||||||
|
if ($csvReadError !== null) {
|
||||||
|
$statusMessage = 'Impossible de vérifier le fichier actions.csv : ' . $csvReadError;
|
||||||
|
} elseif ($csvReady) {
|
||||||
|
$statusMessage = 'Le fichier actions.csv est à jour.';
|
||||||
|
} else {
|
||||||
|
$statusMessage = 'Le fichier actions.csv peut être mis à jour.';
|
||||||
|
if ($csvExists) {
|
||||||
|
$statusMessage .= ' ' . count($differences) . ' différence(s) détectée(s).';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once __DIR__ . '/header.php';
|
||||||
|
?>
|
||||||
|
<section class="csv-shell">
|
||||||
|
<div class="csv-card">
|
||||||
|
<div class="csv-content">
|
||||||
|
<h1>Synchronisation CSV</h1>
|
||||||
|
<p class="csv-status <?= $csvReady ? 'status-ok' : 'status-warning' ?>"><?= htmlspecialchars($statusMessage, ENT_QUOTES, 'UTF-8') ?></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="csv-actions">
|
||||||
|
<?php if ($csvReady): ?>
|
||||||
|
<a href="/php/menu.php" class="btn-action btn-primary">Retour au menu</a>
|
||||||
|
<?php else: ?>
|
||||||
|
<button id="csv-update-yes" type="button" class="btn-action btn-primary">Mettre à jour</button>
|
||||||
|
<button id="csv-update-no" type="button" class="btn-action btn-secondary">Retour au menu</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($csvExists): ?>
|
||||||
|
<a id="csv-download-link" href="/php/download_csv.php" class="btn-action btn-secondary">Télécharger CSV</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="csv-feedback" class="csv-feedback" role="status" aria-live="polite"></div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="/js/csv.js"></script>
|
||||||
|
<?php require_once __DIR__ . '/footer.php';
|
||||||
+267
@@ -71,6 +71,68 @@ class Database
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class CompteJFGManager
|
||||||
|
*
|
||||||
|
* Opérations CRUD sur la table `compteJFG`.
|
||||||
|
*/
|
||||||
|
class CompteJFGManager
|
||||||
|
{
|
||||||
|
private PDO $connection;
|
||||||
|
|
||||||
|
public function __construct(Database $database)
|
||||||
|
{
|
||||||
|
$this->connection = $database->getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listCompteJFG(): array
|
||||||
|
{
|
||||||
|
$statement = $this->connection->query(
|
||||||
|
'SELECT id, date_operation, debit, credit, libelle, updated_at
|
||||||
|
FROM compteJFG
|
||||||
|
ORDER BY date_operation DESC, id DESC'
|
||||||
|
);
|
||||||
|
|
||||||
|
return $statement->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createCompteJFG(array $data): bool
|
||||||
|
{
|
||||||
|
$statement = $this->connection->prepare(
|
||||||
|
'INSERT INTO compteJFG (date_operation, debit, credit, libelle, created_at, updated_at)
|
||||||
|
VALUES (:date_operation, :debit, :credit, :libelle, NOW(), NOW())'
|
||||||
|
);
|
||||||
|
|
||||||
|
$statement->bindValue(':date_operation', $data['date_operation'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':debit', $data['debit'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':credit', $data['credit'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':libelle', $data['libelle'], PDO::PARAM_STR);
|
||||||
|
|
||||||
|
return $statement->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateCompteJFG(int $id, array $data): bool
|
||||||
|
{
|
||||||
|
$statement = $this->connection->prepare(
|
||||||
|
'UPDATE compteJFG
|
||||||
|
SET date_operation = :date_operation,
|
||||||
|
debit = :debit,
|
||||||
|
credit = :credit,
|
||||||
|
libelle = :libelle,
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE id = :id'
|
||||||
|
);
|
||||||
|
|
||||||
|
$statement->bindValue(':date_operation', $data['date_operation'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':debit', $data['debit'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':credit', $data['credit'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':libelle', $data['libelle'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':id', $id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
return $statement->execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class LoginManager
|
* Class LoginManager
|
||||||
*
|
*
|
||||||
@@ -364,3 +426,208 @@ class LoginManager
|
|||||||
return $statement->execute();
|
return $statement->execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ActionsManager
|
||||||
|
*
|
||||||
|
* Opérations CRUD sur la table `actions`.
|
||||||
|
*/
|
||||||
|
class ActionsManager
|
||||||
|
{
|
||||||
|
private PDO $connection;
|
||||||
|
|
||||||
|
public function __construct(Database $database)
|
||||||
|
{
|
||||||
|
$this->connection = $database->getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne toutes les actions.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function listActions(): array
|
||||||
|
{
|
||||||
|
$statement = $this->connection->query(
|
||||||
|
'SELECT isin, ticker, yahoo_code, company_name, updated_at
|
||||||
|
FROM actions
|
||||||
|
ORDER BY updated_at DESC'
|
||||||
|
);
|
||||||
|
|
||||||
|
return $statement->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exporte toutes les actions vers un fichier CSV.
|
||||||
|
*
|
||||||
|
* @param string $filePath
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function exportActionsToCsv(string $filePath): bool
|
||||||
|
{
|
||||||
|
$actions = $this->listActions();
|
||||||
|
|
||||||
|
$directory = dirname($filePath);
|
||||||
|
if (!is_dir($directory) && !mkdir($directory, 0755, true) && !is_dir($directory)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$handle = fopen($filePath, 'w');
|
||||||
|
if ($handle === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$header = ['isin', 'ticker', 'yahoo_code', 'company_name', 'updated_at'];
|
||||||
|
if (fputcsv($handle, $header) === false) {
|
||||||
|
fclose($handle);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($actions as $action) {
|
||||||
|
if (fputcsv($handle, [
|
||||||
|
$action['isin'],
|
||||||
|
$action['ticker'],
|
||||||
|
$action['yahoo_code'],
|
||||||
|
$action['company_name'],
|
||||||
|
$action['updated_at'],
|
||||||
|
]) === false) {
|
||||||
|
fclose($handle);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($handle);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne une action par son ISIN.
|
||||||
|
*
|
||||||
|
* @param string $isin
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function getActionByIsin(string $isin): ?array
|
||||||
|
{
|
||||||
|
$statement = $this->connection->prepare(
|
||||||
|
'SELECT isin, ticker, yahoo_code, company_name, updated_at
|
||||||
|
FROM actions
|
||||||
|
WHERE isin = :isin'
|
||||||
|
);
|
||||||
|
|
||||||
|
$statement->bindValue(':isin', $isin, PDO::PARAM_STR);
|
||||||
|
$statement->execute();
|
||||||
|
|
||||||
|
$result = $statement->fetch();
|
||||||
|
|
||||||
|
return $result === false ? null : $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée une nouvelle action.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function createAction(array $data): bool
|
||||||
|
{
|
||||||
|
$statement = $this->connection->prepare(
|
||||||
|
'INSERT INTO actions (isin, ticker, yahoo_code, company_name, updated_at)
|
||||||
|
VALUES (:isin, :ticker, :yahoo_code, :company_name, NOW())'
|
||||||
|
);
|
||||||
|
|
||||||
|
$statement->bindValue(':isin', $data['isin'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':ticker', $data['ticker'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':yahoo_code', $data['yahoo_code'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':company_name', $data['company_name'], PDO::PARAM_STR);
|
||||||
|
|
||||||
|
return $statement->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Met à jour une action.
|
||||||
|
*
|
||||||
|
* @param string $isin
|
||||||
|
* @param array $data
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function updateAction(string $isin, array $data): bool
|
||||||
|
{
|
||||||
|
$statement = $this->connection->prepare(
|
||||||
|
'UPDATE actions
|
||||||
|
SET ticker = :ticker,
|
||||||
|
yahoo_code = :yahoo_code,
|
||||||
|
company_name = :company_name,
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE isin = :isin'
|
||||||
|
);
|
||||||
|
|
||||||
|
$statement->bindValue(':ticker', $data['ticker'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':yahoo_code', $data['yahoo_code'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':company_name', $data['company_name'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':isin', $isin, PDO::PARAM_STR);
|
||||||
|
|
||||||
|
return $statement->execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class CompteGFManager
|
||||||
|
*
|
||||||
|
* Opérations CRUD sur la table `compteGF`.
|
||||||
|
*/
|
||||||
|
class CompteGFManager
|
||||||
|
{
|
||||||
|
private PDO $connection;
|
||||||
|
|
||||||
|
public function __construct(Database $database)
|
||||||
|
{
|
||||||
|
$this->connection = $database->getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listCompteGF(): array
|
||||||
|
{
|
||||||
|
$statement = $this->connection->query(
|
||||||
|
'SELECT id, date_operation, debit, credit, libelle, updated_at
|
||||||
|
FROM compteGF
|
||||||
|
ORDER BY date_operation DESC, id DESC'
|
||||||
|
);
|
||||||
|
|
||||||
|
return $statement->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createCompteGF(array $data): bool
|
||||||
|
{
|
||||||
|
$statement = $this->connection->prepare(
|
||||||
|
'INSERT INTO compteGF (date_operation, debit, credit, libelle, created_at, updated_at)
|
||||||
|
VALUES (:date_operation, :debit, :credit, :libelle, NOW(), NOW())'
|
||||||
|
);
|
||||||
|
|
||||||
|
$statement->bindValue(':date_operation', $data['date_operation'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':debit', $data['debit'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':credit', $data['credit'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':libelle', $data['libelle'], PDO::PARAM_STR);
|
||||||
|
|
||||||
|
return $statement->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateCompteGF(int $id, array $data): bool
|
||||||
|
{
|
||||||
|
$statement = $this->connection->prepare(
|
||||||
|
'UPDATE compteGF
|
||||||
|
SET date_operation = :date_operation,
|
||||||
|
debit = :debit,
|
||||||
|
credit = :credit,
|
||||||
|
libelle = :libelle,
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE id = :id'
|
||||||
|
);
|
||||||
|
|
||||||
|
$statement->bindValue(':date_operation', $data['date_operation'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':debit', $data['debit'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':credit', $data['credit'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':libelle', $data['libelle'], PDO::PARAM_STR);
|
||||||
|
$statement->bindValue(':id', $id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
return $statement->execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require_once __DIR__ . '/session.php';
|
||||||
|
|
||||||
|
if (empty($_SESSION['user_id'])) {
|
||||||
|
header('Location: ../index.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$csvFilePath = __DIR__ . '/../assets/csv/actions.csv';
|
||||||
|
|
||||||
|
if (!is_readable($csvFilePath)) {
|
||||||
|
http_response_code(404);
|
||||||
|
echo 'Fichier CSV introuvable.';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Content-Type: text/csv; charset=UTF-8');
|
||||||
|
header('Content-Disposition: attachment; filename="actions.csv"');
|
||||||
|
header('Content-Length: ' . (string) filesize($csvFilePath));
|
||||||
|
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||||
|
header('Pragma: no-cache');
|
||||||
|
|
||||||
|
readfile($csvFilePath);
|
||||||
|
exit;
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
</main>
|
</main>
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<?php if (isset($_SESSION['user_id'])): ?>
|
<?php if (isset($_SESSION['user_id'])): ?>
|
||||||
<a class="logout-button footer-logout" href="/php/menu.php?action=logout">Se déconnecter</a>
|
<a class="logout-button footer-logout" href="/php/logout.php">Se déconnecter</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<p>© 2026 - Jean-François GIRAUD - Positions en bourse - Tous droits réservés</p>
|
<p>© 2026 - Jean-François GIRAUD - Positions en bourse - Tous droits réservés</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
+9
-2
@@ -1,13 +1,20 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Bourse - Page d'Accueil</title>
|
<title>Bourse</title>
|
||||||
<link rel="stylesheet" href="/css/style.css">
|
<link rel="stylesheet" href="/css/style.css">
|
||||||
|
<?php if (!empty($pageStylesheets) && is_array($pageStylesheets)): ?>
|
||||||
|
<?php foreach ($pageStylesheets as $sheet): ?>
|
||||||
|
<link rel="stylesheet" href="<?= htmlspecialchars($sheet, ENT_QUOTES, 'UTF-8') ?>">
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
<link rel="shortcut icon" href="/assets/images/favicon.png" type="image/x-icon">
|
<link rel="shortcut icon" href="/assets/images/favicon.png" type="image/x-icon">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
|
||||||
|
<body class="<?= !empty($bodyClass) ? htmlspecialchars($bodyClass, ENT_QUOTES, 'UTF-8') : '' ?>">
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require_once __DIR__ . '/session.php';
|
||||||
|
|
||||||
|
// Destroy the PHP session and clear the session cookie.
|
||||||
|
session_unset();
|
||||||
|
session_destroy();
|
||||||
|
setcookie(session_name(), '', time() - 42000, '/');
|
||||||
|
|
||||||
|
// Redirect to the public login/home page.
|
||||||
|
header('Location: https://giraud-finance.com');
|
||||||
|
exit;
|
||||||
+65
-21
@@ -4,40 +4,84 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
require_once __DIR__ . '/session.php';
|
require_once __DIR__ . '/session.php';
|
||||||
|
|
||||||
// Logout action
|
// Si l'utilisateur n'est pas connecté, redirection vers l'accueil.
|
||||||
if (isset($_GET['action']) && $_GET['action'] === 'logout') {
|
|
||||||
session_unset();
|
|
||||||
session_destroy();
|
|
||||||
setcookie(session_name(), '', time() - 42000, '/');
|
|
||||||
header('Location: ../index.php');
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Require login
|
|
||||||
if (empty($_SESSION['user_id'])) {
|
if (empty($_SESSION['user_id'])) {
|
||||||
header('Location: ../index.php');
|
header('Location: ../index.php');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ajoute le CSS spécifique à cette page et une classe body dédiée.
|
||||||
|
$pageStylesheets = ['/css/menu.css'];
|
||||||
|
$bodyClass = 'menu-page';
|
||||||
|
|
||||||
require_once __DIR__ . '/header.php';
|
require_once __DIR__ . '/header.php';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="login-container">
|
<section class="menu-shell">
|
||||||
<div class="login-box">
|
<article class="menu-card">
|
||||||
<h2 class="login-title">Espace utilisateur</h2>
|
<header class="menu-card__header">
|
||||||
|
<div>
|
||||||
|
<h2 class="menu-card__title">Espace de gestion</h2>
|
||||||
|
<p class="menu-card__subtitle">Accédez aux fonctions clés de l'application financière.</p>
|
||||||
|
</div>
|
||||||
|
<span class="menu-card__badge">v1.0</span>
|
||||||
|
</header>
|
||||||
|
|
||||||
<p>Session ID : <?php echo htmlspecialchars(session_id(), ENT_QUOTES, 'UTF-8'); ?></p>
|
<form name="menu" class="menu-grid" action="#" method="post" autocomplete="off" novalidate>
|
||||||
<p>User ID : <?php echo htmlspecialchars((string)($_SESSION['user_id'] ?? ''), ENT_QUOTES, 'UTF-8'); ?></p>
|
<button type="button" class="menu-button" data-target="/php/ordreGF.php">
|
||||||
<p>Login : <?php echo htmlspecialchars((string)($_SESSION['user_login'] ?? ''), ENT_QUOTES, 'UTF-8'); ?></p>
|
<div class="menu-button__content">
|
||||||
<p>Nom : <?php echo htmlspecialchars((string)($_SESSION['user_name'] ?? ''), ENT_QUOTES, 'UTF-8'); ?></p>
|
<span class="menu-button__title">Ordre GF</span>
|
||||||
<p>Dernière activité (timestamp) : <?php echo htmlspecialchars((string)time(), ENT_QUOTES, 'UTF-8'); ?></p>
|
<span class="menu-button__text">Voir et modifier les ordres GF</span>
|
||||||
<p>Adresse IP : <?php echo htmlspecialchars($_SERVER['REMOTE_ADDR'] ?? '', ENT_QUOTES, 'UTF-8'); ?></p>
|
</div>
|
||||||
|
<span class="menu-button__icon">⇄</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
<div style="margin-top:16px;">
|
<button type="button" class="menu-button" data-target="/php/order_jfg.php">
|
||||||
<a class="btn-submit" href="menu.php?action=logout" style="display:inline-block;text-decoration:none;">Se déconnecter</a>
|
<div class="menu-button__content">
|
||||||
|
<span class="menu-button__title">Ordre JFG</span>
|
||||||
|
<span class="menu-button__text">Voir et modifier les ordres JFG</span>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="menu-button__icon">⇄</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button type="button" class="menu-button" data-target="/php/compteGF.php">
|
||||||
|
<div class="menu-button__content">
|
||||||
|
<span class="menu-button__title">Compte GF</span>
|
||||||
|
<span class="menu-button__text">Voir et modifier le compte GF</span>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="menu-button__icon">💼</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button type="button" class="menu-button" data-target="/php/compteJFG.php">
|
||||||
|
<div class="menu-button__content">
|
||||||
|
<span class="menu-button__title">Compte JFG</span>
|
||||||
|
<span class="menu-button__text">Voir et modifier le compte JFG</span>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="menu-button__icon">💼</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button type="button" class="menu-button" data-target="/php/actions.php">
|
||||||
|
<div class="menu-button__content">
|
||||||
|
<span class="menu-button__title">Actions</span>
|
||||||
|
<span class="menu-button__text">Créer, voir et modifier les actions</span>
|
||||||
|
</div>
|
||||||
|
<span class="menu-button__icon">⚡</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button type="button" class="menu-button" data-target="/php/csv.php">
|
||||||
|
<div class="menu-button__content">
|
||||||
|
<span class="menu-button__title">CSV</span>
|
||||||
|
<span class="menu-button__text">Importer / exporter les actions</span>
|
||||||
|
</div>
|
||||||
|
<span class="menu-button__icon">📁</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p class="menu-note">Giraud Finance : Accès sécurisé. Veillez à fermer votre session après chaque utilisation.</p>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="/js/menu.js" defer></script>
|
||||||
|
|
||||||
<?php require_once __DIR__ . '/footer.php'; ?>
|
<?php require_once __DIR__ . '/footer.php'; ?>
|
||||||
|
|
||||||
|
|||||||
+339
@@ -0,0 +1,339 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
require_once __DIR__ . '/session.php';
|
||||||
|
require_once __DIR__ . '/db.php';
|
||||||
|
|
||||||
|
if (empty($_SESSION['user_id'])) {
|
||||||
|
header('Location: ../index.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
ini_set('display_startup_errors', 1);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
$pageStylesheets = ['/css/ordreGF.css'];
|
||||||
|
$bodyClass = 'ordregf-page';
|
||||||
|
|
||||||
|
$database = new App\Database\Database();
|
||||||
|
$connection = $database->getConnection();
|
||||||
|
|
||||||
|
// --- Fonctions ---
|
||||||
|
function fetchOrdreGF(PDO $connection): array
|
||||||
|
{
|
||||||
|
$query = 'SELECT * FROM `ordreGF` ORDER BY `ID` DESC';
|
||||||
|
$stmt = $connection->query($query);
|
||||||
|
return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchOrdreGFPied(PDO $connection, string $masterId): array
|
||||||
|
{
|
||||||
|
$stmt = $connection->prepare('SELECT * FROM `ordreGF_pied` WHERE `Id_entete` = :masterId ORDER BY `Id` ASC');
|
||||||
|
$stmt->execute([':masterId' => $masterId]);
|
||||||
|
return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$ordres = fetchOrdreGF($connection);
|
||||||
|
|
||||||
|
require_once __DIR__ . '/header.php';
|
||||||
|
?>
|
||||||
|
<section class="ordregf-shell">
|
||||||
|
<div class="ordregf-card">
|
||||||
|
<header class="ordregf-card-header" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 28px;">
|
||||||
|
<h1 class="ordregf-title">Gestion des ordres GF</h1>
|
||||||
|
|
||||||
|
<div style="display: flex; gap: 10px;">
|
||||||
|
<button type="button" class="ordregf-btn-creer" onclick="document.getElementById('modalCreerOrdre').showModal();">
|
||||||
|
Créer un ordre
|
||||||
|
</button>
|
||||||
|
<button type="button" class="ordregf-btn-menu" onclick="window.location.href='/php/menu.php';">
|
||||||
|
Retour au menu
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="ordregf-table-wrapper">
|
||||||
|
<table class="ordregf-table">
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($ordres as $ordre): ?>
|
||||||
|
<?php
|
||||||
|
// Pré-calcul pour les boutons
|
||||||
|
$details = fetchOrdreGFPied($connection, (string)$ordre['ID']);
|
||||||
|
$totalQ = 0;
|
||||||
|
foreach ($details as $d) {
|
||||||
|
$q = (int)($d['Quantite'] ?? 0);
|
||||||
|
$oType = strtolower($d['Ordre'] ?? '');
|
||||||
|
$tOp = strtolower($d['Type'] ?? '');
|
||||||
|
if (strtolower($d['Etat'] ?? '') === 'actif') {
|
||||||
|
$totalQ += ($tOp === 'long' ? ($oType === 'achat' ? $q : -$q) : ($oType === 'achat' ? -$q : $q));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$isSold = ($totalQ === 0 && count($details) > 0);
|
||||||
|
// Désactiver si vendu OU si une plus-value existe déjà
|
||||||
|
$isDisabled = $isSold || (isset($ordre['PlusValue']) && (float)$ordre['PlusValue'] !== 0.0);
|
||||||
|
$disabledAttr = $isDisabled ? 'disabled style="opacity:0.5; cursor:not-allowed;"' : '';
|
||||||
|
?>
|
||||||
|
|
||||||
|
<tr class="ordregf-master-row ordregf-header-style">
|
||||||
|
<td colspan="11" style="font-weight: bold; font-size: 1.1em; color: #fff;">
|
||||||
|
<?php echo htmlspecialchars((string)$ordre['isin']) . ' --- ' . htmlspecialchars((string)$ordre['Nom']) . ' ( ' . htmlspecialchars((string)$ordre['ticker']) . ' )'; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="ordregf-detail-block">
|
||||||
|
<td colspan="11">
|
||||||
|
<table class="ordregf-detail-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Qté</th>
|
||||||
|
<th>Prix Brut</th>
|
||||||
|
<th>Frais</th>
|
||||||
|
<th>Prix Net</th>
|
||||||
|
<th>Engagement Brut</th>
|
||||||
|
<th>Engagement Net</th>
|
||||||
|
<th>Ordre</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Etat</th>
|
||||||
|
<th style="text-align: right;">
|
||||||
|
<button type="button" class="ordregf-btn-petit ordregf-btn-creer-petit"
|
||||||
|
<?= $disabledAttr ?>
|
||||||
|
onclick="document.getElementById('Id_entete_detail').value='<?= $ordre['ID'] ?>'; document.getElementById('modalCreerDetail').showModal();">
|
||||||
|
Créer
|
||||||
|
</button>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php
|
||||||
|
$engaBrut = 0;
|
||||||
|
$engaNet = 0;
|
||||||
|
|
||||||
|
foreach ($details as $detail):
|
||||||
|
$qte = (int)($detail['Quantite'] ?? 0);
|
||||||
|
$prix = (float)($detail['Prix_brut'] ?? 0);
|
||||||
|
$frais = (float)($detail['Frais_brocker'] ?? 0) + (float)($detail['Frais_etat'] ?? 0) + (float)($detail['Frais_autre'] ?? 0);
|
||||||
|
$prixNet = $prix + $frais;
|
||||||
|
$date = !empty($detail['Date_op']) ? date('d/m/Y', strtotime($detail['Date_op'])) : '--/--/----';
|
||||||
|
|
||||||
|
$ordre_type = strtolower($detail['Ordre'] ?? '');
|
||||||
|
$type_op = strtolower($detail['Type'] ?? '');
|
||||||
|
$etat = strtolower($detail['Etat'] ?? '');
|
||||||
|
|
||||||
|
if ($etat === 'actif') {
|
||||||
|
if ($type_op === 'long') {
|
||||||
|
if ($ordre_type === 'achat') {
|
||||||
|
$engaBrut += $qte * $prix;
|
||||||
|
$engaNet += $qte * $prixNet;
|
||||||
|
} else {
|
||||||
|
$engaBrut -= $qte * $prix;
|
||||||
|
$engaNet -= $qte * $prixNet;
|
||||||
|
}
|
||||||
|
} elseif ($type_op === 'short') {
|
||||||
|
if ($ordre_type === 'achat') {
|
||||||
|
$engaBrut -= $qte * $prix;
|
||||||
|
$engaNet -= $qte * $prixNet;
|
||||||
|
} else {
|
||||||
|
$engaBrut += $qte * $prix;
|
||||||
|
$engaNet += $qte * $prixNet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<tr class="ordregf-detail-row">
|
||||||
|
<td><?= htmlspecialchars($date) ?></td>
|
||||||
|
<td class="text-right"><?= number_format($qte, 0, ',', ' ') ?></td>
|
||||||
|
<td class="text-right"><?= number_format($prix, 3, ',', ' ') ?></td>
|
||||||
|
<td class="text-right"><?= number_format($frais, 3, ',', ' ') ?></td>
|
||||||
|
<td class="text-right"><?= number_format($prixNet, 3, ',', ' ') ?></td>
|
||||||
|
<td class="text-right"><?= number_format($qte * $prix, 3, ',', ' ') ?></td>
|
||||||
|
<td class="text-right"><?= number_format($qte * $prixNet, 3, ',', ' ') ?></td>
|
||||||
|
<td><?= htmlspecialchars($detail['Ordre'] ?? '') ?></td>
|
||||||
|
<td><?= htmlspecialchars($detail['Type'] ?? '') ?></td>
|
||||||
|
<td><?= htmlspecialchars($detail['Etat'] ?? '') ?></td>
|
||||||
|
<td style="text-align: right;">
|
||||||
|
<button type="button" class="ordregf-btn-petit ordregf-btn-modifier-petit"
|
||||||
|
<?= $disabledAttr ?>
|
||||||
|
data-detail='<?= htmlspecialchars(json_encode($detail), ENT_QUOTES, 'UTF-8') ?>'>
|
||||||
|
Modifier
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$plusvalue = 0.0000;
|
||||||
|
if ($isSold) {
|
||||||
|
foreach ($details as $detail) {
|
||||||
|
$qte = (int)$detail['Quantite'];
|
||||||
|
$prixNet = (float)$detail['Prix_brut'] + (float)$detail['Frais_brocker'] + (float)$detail['Frais_etat'] + (float)$detail['Frais_autre'];
|
||||||
|
$eNet = round($qte * $prixNet, 4);
|
||||||
|
$oType = strtolower($detail['Ordre']);
|
||||||
|
$tOp = strtolower($detail['Type']);
|
||||||
|
$signe = ($tOp === 'long') ? (($oType === 'vente') ? 1 : -1) : (($oType === 'achat') ? 1 : -1);
|
||||||
|
$plusvalue += ($eNet * $signe);
|
||||||
|
}
|
||||||
|
$plusvalue = round($plusvalue, 4);
|
||||||
|
if (abs((float)$ordre['PlusValue'] - $plusvalue) > 0.0001) {
|
||||||
|
$connection->prepare("UPDATE ordreGF SET PlusValue = ? WHERE ID = ?")->execute([$plusvalue, $ordre['ID']]);
|
||||||
|
$connection->prepare("UPDATE ordreGF_pied SET Etat = 'soldé' WHERE Id_entete = ? AND Etat != 'soldé'")->execute([$ordre['ID']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php if ($isSold): ?>
|
||||||
|
<tr style="background-color: rgba(255, 255, 255, 0.08); font-weight: bold;">
|
||||||
|
<td colspan="6" style="text-align: right;">Plus value :</td>
|
||||||
|
<td class="text-right" style="color: <?= $plusvalue < 0 ? 'red' : 'green' ?>;">
|
||||||
|
<?= number_format((float)($ordre['PlusValue'] ?: $plusvalue), 3, ',', ' ') ?>
|
||||||
|
</td>
|
||||||
|
<td colspan="4"></td>
|
||||||
|
</tr>
|
||||||
|
<?php else: ?>
|
||||||
|
<tr style="background-color: rgba(255, 255, 255, 0.08); font-weight: bold;">
|
||||||
|
<td style="text-align: right;">TOTAL :</td>
|
||||||
|
<td class="text-right"><?= number_format($totalQ, 0, ',', ' ') ?></td>
|
||||||
|
<?php if ($totalQ == 0): ?>
|
||||||
|
<td class="text-right">0</td>
|
||||||
|
<td class="text-right">0</td>
|
||||||
|
<td class="text-right">0</td>
|
||||||
|
<?php else: ?>
|
||||||
|
<td class="text-right"><?= number_format($engaBrut / $totalQ, 3, ',', ' ') ?></td>
|
||||||
|
<td class="text-right"><?= number_format($engaNet / $totalQ - $engaBrut / $totalQ, 3, ',', ' ') ?></td>
|
||||||
|
<td class="text-right"><?= number_format($engaNet / $totalQ, 3, ',', ' ') ?></td>
|
||||||
|
<?php endif; ?>
|
||||||
|
<td class="text-right"><?= number_format($engaBrut, 3, ',', ' ') ?></td>
|
||||||
|
<td class="text-right"><?= number_format($engaNet, 3, ',', ' ') ?></td>
|
||||||
|
<td colspan="4"></td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Modals -->
|
||||||
|
<dialog id="modalCreerOrdre" class="ordregf-modal">
|
||||||
|
<form id="formCreerOrdre">
|
||||||
|
<h2>Créer un nouvel ordre</h2>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>ISIN :</label><br>
|
||||||
|
<input type="text" id="isinRecherche" name="isin" required>
|
||||||
|
<button type="button" id="btnRechercher">Rechercher</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Nom :</label><br>
|
||||||
|
<input type="text" name="Nom" id="Nom" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Ticker :</label><br>
|
||||||
|
<input type="text" name="ticker" id="ticker" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Code Yahoo :</label><br>
|
||||||
|
<input type="text" name="code_yahoo" id="code_yahoo" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="modal-actions" style="margin-top: 20px;">
|
||||||
|
<button type="button" id="btnAnnuler">Annuler</button>
|
||||||
|
<button type="submit" id="btnValider" disabled>Valider</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<dialog id="modalCreerDetail" class="ordregf-modal">
|
||||||
|
<form id="formCreerDetail">
|
||||||
|
<input type="hidden" name="Id_entete" id="Id_entete_detail">
|
||||||
|
<h2>Ajouter un mouvement</h2>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Date :</label><br>
|
||||||
|
<input type="date" name="Date_op" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Quantité :</label><br>
|
||||||
|
<input type="number" name="Quantite" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Prix Brut :</label><br>
|
||||||
|
<input type="number" step="0.001" name="Prix_brut" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Frais (Broker / Etat / Autre) :</label><br>
|
||||||
|
<input type="number" step="0.01" name="Frais_brocker" placeholder="Broker">
|
||||||
|
<input type="number" step="0.01" name="Frais_etat" placeholder="Etat">
|
||||||
|
<input type="number" step="0.01" name="Frais_autre" placeholder="Autre">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Ordre (Achat/Vente) :</label>
|
||||||
|
<select name="Ordre">
|
||||||
|
<option value="Achat">Achat</option>
|
||||||
|
<option value="Vente">Vente</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Type (Long/Short) :</label>
|
||||||
|
<select name="Type">
|
||||||
|
<option value="Long">Long</option>
|
||||||
|
<option value="Short">Short</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Etat :</label>
|
||||||
|
<select name="Etat">
|
||||||
|
<option value="Actif">Actif</option>
|
||||||
|
<option value="Cloture">Cloture</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="modal-actions" style="margin-top: 20px;">
|
||||||
|
<button type="button" onclick="document.getElementById('modalCreerDetail').close()">Annuler</button>
|
||||||
|
<button type="submit">Valider</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<dialog id="modalModifierDetail" class="ordregf-modal">
|
||||||
|
<form id="formModifierDetail">
|
||||||
|
<input type="hidden" name="id" id="edit_id">
|
||||||
|
<input type="hidden" name="Id_entete" id="edit_Id_entete">
|
||||||
|
<h2>Modifier le mouvement</h2>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Date :</label><br>
|
||||||
|
<input type="date" name="Date_op" id="edit_date" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Quantité :</label><br>
|
||||||
|
<input type="number" name="Quantite" id="edit_quantite" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Prix Brut :</label><br>
|
||||||
|
<input type="number" step="0.001" name="Prix_brut" id="edit_prix" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Frais :</label><br>
|
||||||
|
<input type="number" step="0.01" name="Frais_brocker" id="edit_frais_broker" placeholder="Broker">
|
||||||
|
<input type="number" step="0.01" name="Frais_etat" id="edit_frais_etat" placeholder="Etat">
|
||||||
|
<input type="number" step="0.01" name="Frais_autre" id="edit_frais_autre" placeholder="Autre">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Ordre :</label>
|
||||||
|
<select name="Ordre" id="edit_ordre">
|
||||||
|
<option value="Achat">Achat</option>
|
||||||
|
<option value="Vente">Vente</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="modal-actions" style="margin-top: 20px;">
|
||||||
|
<button type="button" onclick="document.getElementById('modalModifierDetail').close()">Annuler</button>
|
||||||
|
<button type="submit">Enregistrer</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<script src="/js/ordreGF.js" defer></script>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/footer.php'; ?>
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require_once __DIR__ . '/session.php';
|
||||||
|
require_once __DIR__ . '/db.php';
|
||||||
|
|
||||||
|
use App\Database\Database;
|
||||||
|
use App\Database\ActionsManager;
|
||||||
|
|
||||||
|
header('Content-Type: application/json; charset=UTF-8');
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
http_response_code(405);
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Méthode non autorisée.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($_SESSION['user_id'])) {
|
||||||
|
http_response_code(401);
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Authentification requise.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$database = new Database();
|
||||||
|
$actionsManager = new ActionsManager($database);
|
||||||
|
$csvFilePath = __DIR__ . '/../assets/csv/actions.csv';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$success = $actionsManager->exportActionsToCsv($csvFilePath);
|
||||||
|
if (!$success) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Impossible de générer le fichier CSV.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'message' => 'Fichier CSV mis à jour avec succès.']);
|
||||||
|
exit;
|
||||||
|
} catch (Throwable $exception) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Erreur interne : ' . $exception->getMessage()]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
+120
-4
@@ -1,6 +1,7 @@
|
|||||||
.
|
.
|
||||||
├── assets
|
├── assets
|
||||||
│ ├── csv
|
│ ├── csv
|
||||||
|
│ │ ├── actions.csv
|
||||||
│ │ ├── autre.csv
|
│ │ ├── autre.csv
|
||||||
│ │ ├── ibex35.csv
|
│ │ ├── ibex35.csv
|
||||||
│ │ ├── nasdaq100.csv
|
│ │ ├── nasdaq100.csv
|
||||||
@@ -9,18 +10,133 @@
|
|||||||
│ └── images
|
│ └── images
|
||||||
│ ├── favicon.png
|
│ ├── favicon.png
|
||||||
│ └── GFBlancLogo.png
|
│ └── GFBlancLogo.png
|
||||||
|
├── composer.json
|
||||||
|
├── composer.lock
|
||||||
├── css
|
├── css
|
||||||
|
│ ├── 404.css
|
||||||
|
│ ├── actions.css
|
||||||
|
│ ├── compteGF.css
|
||||||
|
│ ├── compteJFG.css
|
||||||
|
│ ├── csv.css
|
||||||
|
│ ├── menu.css
|
||||||
│ └── style.css
|
│ └── style.css
|
||||||
├── .htaccess
|
|
||||||
├── index.php
|
├── index.php
|
||||||
├── js
|
├── js
|
||||||
|
│ ├── actions.js
|
||||||
|
│ ├── compteGF.js
|
||||||
|
│ ├── compteJFG.js
|
||||||
|
│ ├── csv.js
|
||||||
|
│ └── menu.js
|
||||||
├── php
|
├── php
|
||||||
│ ├── 404.php
|
│ ├── 404.php
|
||||||
|
│ ├── actions.php
|
||||||
|
│ ├── compteGF.php
|
||||||
|
│ ├── compteJFG.php
|
||||||
|
│ ├── csv.php
|
||||||
|
│ ├── db.php
|
||||||
|
│ ├── download_csv.php
|
||||||
│ ├── footer.php
|
│ ├── footer.php
|
||||||
|
│ ├── forgot_password.php
|
||||||
│ ├── header.php
|
│ ├── header.php
|
||||||
|
│ ├── login_process.php
|
||||||
|
│ ├── logout.php
|
||||||
│ ├── menu.php
|
│ ├── menu.php
|
||||||
│ └── session.php
|
│ ├── register.php
|
||||||
|
│ ├── reset_password.php
|
||||||
|
│ ├── session.php
|
||||||
|
│ └── update_csv.php
|
||||||
├── structure.txt
|
├── structure.txt
|
||||||
└── structur.txt
|
└── vendor
|
||||||
|
├── autoload.php
|
||||||
|
├── composer
|
||||||
|
│ ├── autoload_classmap.php
|
||||||
|
│ ├── autoload_namespaces.php
|
||||||
|
│ ├── autoload_psr4.php
|
||||||
|
│ ├── autoload_real.php
|
||||||
|
│ ├── autoload_static.php
|
||||||
|
│ ├── ClassLoader.php
|
||||||
|
│ ├── installed.json
|
||||||
|
│ ├── installed.php
|
||||||
|
│ ├── InstalledVersions.php
|
||||||
|
│ ├── LICENSE
|
||||||
|
│ └── platform_check.php
|
||||||
|
└── phpmailer
|
||||||
|
└── phpmailer
|
||||||
|
├── COMMITMENT
|
||||||
|
├── composer.json
|
||||||
|
├── get_oauth_token.php
|
||||||
|
├── language
|
||||||
|
│ ├── phpmailer.lang-af.php
|
||||||
|
│ ├── phpmailer.lang-ar.php
|
||||||
|
│ ├── phpmailer.lang-as.php
|
||||||
|
│ ├── phpmailer.lang-az.php
|
||||||
|
│ ├── phpmailer.lang-ba.php
|
||||||
|
│ ├── phpmailer.lang-be.php
|
||||||
|
│ ├── phpmailer.lang-bg.php
|
||||||
|
│ ├── phpmailer.lang-bn.php
|
||||||
|
│ ├── phpmailer.lang-ca.php
|
||||||
|
│ ├── phpmailer.lang-cs.php
|
||||||
|
│ ├── phpmailer.lang-da.php
|
||||||
|
│ ├── phpmailer.lang-de.php
|
||||||
|
│ ├── phpmailer.lang-el.php
|
||||||
|
│ ├── phpmailer.lang-eo.php
|
||||||
|
│ ├── phpmailer.lang-es.php
|
||||||
|
│ ├── phpmailer.lang-et.php
|
||||||
|
│ ├── phpmailer.lang-fa.php
|
||||||
|
│ ├── phpmailer.lang-fi.php
|
||||||
|
│ ├── phpmailer.lang-fo.php
|
||||||
|
│ ├── phpmailer.lang-fr.php
|
||||||
|
│ ├── phpmailer.lang-gl.php
|
||||||
|
│ ├── phpmailer.lang-he.php
|
||||||
|
│ ├── phpmailer.lang-hi.php
|
||||||
|
│ ├── phpmailer.lang-hr.php
|
||||||
|
│ ├── phpmailer.lang-hu.php
|
||||||
|
│ ├── phpmailer.lang-hy.php
|
||||||
|
│ ├── phpmailer.lang-id.php
|
||||||
|
│ ├── phpmailer.lang-it.php
|
||||||
|
│ ├── phpmailer.lang-ja.php
|
||||||
|
│ ├── phpmailer.lang-ka.php
|
||||||
|
│ ├── phpmailer.lang-ko.php
|
||||||
|
│ ├── phpmailer.lang-ku.php
|
||||||
|
│ ├── phpmailer.lang-lt.php
|
||||||
|
│ ├── phpmailer.lang-lv.php
|
||||||
|
│ ├── phpmailer.lang-mg.php
|
||||||
|
│ ├── phpmailer.lang-mn.php
|
||||||
|
│ ├── phpmailer.lang-ms.php
|
||||||
|
│ ├── phpmailer.lang-nb.php
|
||||||
|
│ ├── phpmailer.lang-nl.php
|
||||||
|
│ ├── phpmailer.lang-pl.php
|
||||||
|
│ ├── phpmailer.lang-pt_br.php
|
||||||
|
│ ├── phpmailer.lang-pt.php
|
||||||
|
│ ├── phpmailer.lang-ro.php
|
||||||
|
│ ├── phpmailer.lang-ru.php
|
||||||
|
│ ├── phpmailer.lang-si.php
|
||||||
|
│ ├── phpmailer.lang-sk.php
|
||||||
|
│ ├── phpmailer.lang-sl.php
|
||||||
|
│ ├── phpmailer.lang-sr_latn.php
|
||||||
|
│ ├── phpmailer.lang-sr.php
|
||||||
|
│ ├── phpmailer.lang-sv.php
|
||||||
|
│ ├── phpmailer.lang-tl.php
|
||||||
|
│ ├── phpmailer.lang-tr.php
|
||||||
|
│ ├── phpmailer.lang-uk.php
|
||||||
|
│ ├── phpmailer.lang-ur.php
|
||||||
|
│ ├── phpmailer.lang-vi.php
|
||||||
|
│ ├── phpmailer.lang-zh_cn.php
|
||||||
|
│ └── phpmailer.lang-zh.php
|
||||||
|
├── LICENSE
|
||||||
|
├── README.md
|
||||||
|
├── SECURITY.md
|
||||||
|
├── SMTPUTF8.md
|
||||||
|
├── src
|
||||||
|
│ ├── DSNConfigurator.php
|
||||||
|
│ ├── Exception.php
|
||||||
|
│ ├── OAuth.php
|
||||||
|
│ ├── OAuthTokenProvider.php
|
||||||
|
│ ├── PHPMailer.php
|
||||||
|
│ ├── POP3.php
|
||||||
|
│ └── SMTP.php
|
||||||
|
└── VERSION
|
||||||
|
|
||||||
7 directories, 17 files
|
13 directories, 125 files
|
||||||
|
|
||||||
|
tree > structure.txt
|
||||||
|
|||||||
Reference in New Issue
Block a user