IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

IHM Discussion :

Afficher des enregistrements dans un état selon un critère


Sujet :

IHM

  1. #1
    Membre éprouvé Avatar de azertix
    Homme Profil pro
    Technicien d'assistance informatique
    Inscrit en
    Juin 2007
    Messages
    958
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien d'assistance informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 958
    Points : 937
    Points
    937
    Par défaut Afficher des enregistrements dans un état selon un critère
    Bonjour à tous.
    Comme l'indique le titre, je souhaiterais afficher les informations d'un état suivant un critère qui est un numéro présent dans la zone de liste lstNotes en colonne 0.

    Donc, pour résumer, je clique sur le bouton cmdImprimer, et là s'ouvre mon état avec les infos de ma BDD suivant un critère qui est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Forms![lstNotes].Column(0)
    Actuellement, les informations affichées dans l'état sont affichées en fonction d'une requète Access. Le contenu des zones de texte de mon état ressemble à ça :
    Requête 3.[MonChamp]
    A l'heure actuelle, les informations sont bien affichées, mais affichent toujours les infos concernant la première ligne de ma ZdL, quelle que soit la ligne sélectionnée. D'où l'intérêt de créer un critère.

    Mon code était auparavant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Private Sub cmdImprimer_Click()
        DoCmd.OpenReport "etaImpr", acViewPreview
    End Sub
    Après j'ai ajouté un critère :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Private Sub cmdImprimer_Click()
        Dim critere As String
        Dim tAvoir As Recordset
        Set bd = CurrentDb
        Set tAvoir = bd.OpenRecordset("Avoir", DB_OPEN_DYNASET)
        critere = "tAvoir![NumNote]=" & Me.lstNotes.Column(0)
        DoCmd.OpenReport "etaImpr", acViewPreview, , critere
    End Sub
    Et comme ça marchait pas, j'ai essayé en mettant la requète dans le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Private Sub cmdImprimer_Click()
        Dim req As String
        req = "SELECT N.NumNote AS N°Note, N.DateNote, C.NumContrat AS N°Cont, C.DateEnregContrat AS DateEnreg, Cl.NumCli AS N°Cli, Cl.NomCli AS Nom, C.DateEffetContrat, C.NatureContrat, V.NomVendeur, S.PrenomEmploye, M.LibMotif, A.NumAgence, M.NumMotif, S.TelEmploye, S.NomEmploye, A.NomAgence, N.ComNote " _
        & "FROM NOTES AS N, CONTRAT AS C, CLIENT AS Cl, AGENCE AS A, VENDEUR AS V, SERV_ASSU AS S, MOTIF AS M, Avoir AS Av " _
        & "WHERE C.NumContrat = N.NumContrat " _
        & "And C.NumCli = Cl.NumCli " _
        & "And C.NumAgence = A.NumAgence " _
        & "And C.NumVendeur = V.NumVendeur " _
        & "And N.NumEmploye = S.NumEmploye " _
        & "And M.NumMotif = Av.NumMotif " _
        & "And Av.NumNote = N.NumNote " _
        & "And Av.NumNote =" & Forms![frmContratIrregulier].lstNotes.Column(0) & ";"
        'MsgBox req
        DoCmd.OpenReport "etaImpr", acViewPreview, req
    End Sub
    Et ça, ça ne marche pas non plus. Alors, je sais pas si ça vient du code, ou de mon état
    Si ma réponse vous a été utile pensez à voter Pour

    Avant de poster sur le forum Access :
    FAQ > SOURCES > COURS > FORUM > GOOGLE
    Pas de question par MP ou je mords


  2. #2
    Rédacteur/Modérateur
    Avatar de Jeannot45
    Homme Profil pro
    Retraité
    Inscrit en
    Octobre 2004
    Messages
    3 871
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 75
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Enseignement

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 871
    Points : 8 489
    Points
    8 489
    Par défaut


    Tu nous dit que :

    Actuellement, les informations affichées dans l'état sont affichées en fonction d'une requète Access
    Donc la source de ton état existe., Il est inutile de recréer un jeu d'enregistrements (Recordset)

    La ligne de code suivante devrait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.OpenReport "etaImpr", acViewPreview,,"MonChamp = " & lstNotes
    Remarque : si la valeur de lstNotes est alpha, ton code s'écrira :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.OpenReport "etaImpr", acViewPreview,,"MonChamp = '" & lstNotes & "'"
    Si ta colonne liée de la source de ta liste lstNotes est la première colonne, il est inutile de mentionner

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Forms![lstNotes].Column(0)
    Jeannot

    Liens Office indispensables à visiter: Cours (Tutos), F.A.Q., Sources VBA

    Ne posez pas de questions par MP, je n'ai pas le temps d'y répondre

  3. #3
    Membre éprouvé Avatar de azertix
    Homme Profil pro
    Technicien d'assistance informatique
    Inscrit en
    Juin 2007
    Messages
    958
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien d'assistance informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 958
    Points : 937
    Points
    937
    Par défaut
    Rebonjour
    Alors, ça me fait pareil qu'avec la solution que j'ai testé avec le critère :
    quand je clique sur mon bouton, il me demande d'entrer "la valeur du paramètre" pour NumNote :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.OpenReport "etaImpr", acViewPreview, , "[NumNote] = " & lstNotes
    Si ma réponse vous a été utile pensez à voter Pour

    Avant de poster sur le forum Access :
    FAQ > SOURCES > COURS > FORUM > GOOGLE
    Pas de question par MP ou je mords


  4. #4
    Rédacteur/Modérateur
    Avatar de Jeannot45
    Homme Profil pro
    Retraité
    Inscrit en
    Octobre 2004
    Messages
    3 871
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 75
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Enseignement

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 871
    Points : 8 489
    Points
    8 489
    Par défaut
    Est ce que le champ NumNote est posé sur ton état. Sinon, tu le poses eet tu le rends invisible si celui-ci n'est pas utile à l'affichage. Il doit néanmoins être sur l'état
    Jeannot

    Liens Office indispensables à visiter: Cours (Tutos), F.A.Q., Sources VBA

    Ne posez pas de questions par MP, je n'ai pas le temps d'y répondre

  5. #5
    Membre éprouvé Avatar de azertix
    Homme Profil pro
    Technicien d'assistance informatique
    Inscrit en
    Juin 2007
    Messages
    958
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien d'assistance informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 958
    Points : 937
    Points
    937
    Par défaut
    J'ai ajouté une zone de texte sur mon état, qui contient bien le numéro de note. La propriété Source contrôle contient :
    Requête3.NumNote
    Sinon, j'ai cette erreur maintenant :
    Images attachées Images attachées  
    Si ma réponse vous a été utile pensez à voter Pour

    Avant de poster sur le forum Access :
    FAQ > SOURCES > COURS > FORUM > GOOGLE
    Pas de question par MP ou je mords


  6. #6
    Rédacteur/Modérateur
    Avatar de Jeannot45
    Homme Profil pro
    Retraité
    Inscrit en
    Octobre 2004
    Messages
    3 871
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 75
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Enseignement

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 871
    Points : 8 489
    Points
    8 489
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    J'ai ajouté une zone de texte sur mon état, qui contient bien le numéro de note. La propriété Source contrôle contient :
    
    Citation:
    Requête3.NatureContrat 
    Qu'est ce que ce NumNote alors?

    Est-ce un champ de la requete ? Sans doute que OUI vu le message que tu me montres. Celui-ci signifie que le champ NumNote se trouve dans plusieurs tables de ta requete.
    Il faut donc que tu précises le nom de la table source

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.OpenReport "etaImpr", acViewPreview, , "[TableSource].[NumNote] = " & lstNotes
    D'autre part, si tu fais référence à NatureContrat, ton code doit changer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.OpenReport "etaImpr", acViewPreview, , "[NatureContrat] = " & lstNotes
    Je t'avoue que je commence à
    Jeannot

    Liens Office indispensables à visiter: Cours (Tutos), F.A.Q., Sources VBA

    Ne posez pas de questions par MP, je n'ai pas le temps d'y répondre

  7. #7
    Membre éprouvé Avatar de azertix
    Homme Profil pro
    Technicien d'assistance informatique
    Inscrit en
    Juin 2007
    Messages
    958
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien d'assistance informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 958
    Points : 937
    Points
    937
    Par défaut
    C'est normal que tu commences à , c'est moi qui dis des ***neries.
    Ma zone de texte sur mon état, contient
    Requête3.NumNote
    et non :
    Requête3.NatureContrat
    J'ai fait un copier coller foireux

    Sinon, même quand je mentionne la table source, Access me demande la valeur.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.OpenReport "etaImpr", acViewPreview, , "[Avoir].[NumNote] = " & lstNotes
    Si ma réponse vous a été utile pensez à voter Pour

    Avant de poster sur le forum Access :
    FAQ > SOURCES > COURS > FORUM > GOOGLE
    Pas de question par MP ou je mords


  8. #8
    Expert confirmé
    Avatar de vodiem
    Homme Profil pro
    Vivre
    Inscrit en
    Avril 2006
    Messages
    2 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Vivre
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2006
    Messages : 2 895
    Points : 4 325
    Points
    4 325
    Par défaut
    salut azertix et Jeannot45,

    Jeannot45> je tape l'incruste pour aider mon compatriote azertix

    azertix> j'ai vu déjà dans un code que tu avais fourni une erreur de conception que tu reprends ici:
    Code azertix : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Private Sub cmdImprimer_Click()
        Dim critere As String
        Dim tAvoir As Recordset
        Set bd = CurrentDb
        Set tAvoir = bd.OpenRecordset("Avoir", DB_OPEN_DYNASET)
        critere = "tAvoir![NumNote]=" & Me.lstNotes.Column(0)
        DoCmd.OpenReport "etaImpr", acViewPreview, , critere
    End Sub
    lorsque tu ouvres ton "etatImpr" il y a déjà une source de donnée défini (en principe), ce n'est pas en créant un recordset "Avoir" (surtout sans l'affecter à l'état) que tu pourras le changer.
    d'ailleurs les champs de l'état étant crée en fonction de la source il n'est pas recommandé de la modifier, sauf en pleine connaissance de cause.

    dans l'état tu retrouves dans 'ajouter des champs existants' (access 2007) l'ensemble des champs disponibles dans ton état sur lequel tu peux appliquer ton filtre.
    si tu avais "Avoir" comme source de ton état:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.OpenReport "etaImpr", acViewPreview, , "[NumNote] = " & CStr(lstNotes)
    tu peux aussi faire des essais préalable: "[NumNote]=1"
    mais puisque tu as Requête3, assure toi qu'il y a bien NumNote parmi ses champs.
    et si tu tiens à mentionner la source de la table: mentionne celle qui est présente dans la source de ton état...

  9. #9
    Rédacteur/Modérateur
    Avatar de Jeannot45
    Homme Profil pro
    Retraité
    Inscrit en
    Octobre 2004
    Messages
    3 871
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 75
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Enseignement

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 871
    Points : 8 489
    Points
    8 489
    Par défaut
    Merci Vodiem pour ce coup de main

    P.S : A propos d'autre chose, tu trouveras dans ma signature un lien vers le tuto de planning (partie 1) qui est maintenant en ligne. je ne sais pas si tu as pu résoudre ton problème d'affichage.

    Bonne journée
    Jeannot

    Liens Office indispensables à visiter: Cours (Tutos), F.A.Q., Sources VBA

    Ne posez pas de questions par MP, je n'ai pas le temps d'y répondre

  10. #10
    Membre éprouvé Avatar de azertix
    Homme Profil pro
    Technicien d'assistance informatique
    Inscrit en
    Juin 2007
    Messages
    958
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien d'assistance informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 958
    Points : 937
    Points
    937
    Par défaut
    Citation Envoyé par vodiem Voir le message
    salut azertix et Jeannot45,

    Jeannot45> je tape l'incruste pour aider mon compatriote azertix

    azertix> j'ai vu déjà dans un code que tu avais fourni une erreur de conception que tu reprends ici:
    Code azertix : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Private Sub cmdImprimer_Click()
        Dim critere As String
        Dim tAvoir As Recordset
        Set bd = CurrentDb
        Set tAvoir = bd.OpenRecordset("Avoir", DB_OPEN_DYNASET)
        critere = "tAvoir![NumNote]=" & Me.lstNotes.Column(0)
        DoCmd.OpenReport "etaImpr", acViewPreview, , critere
    End Sub
    lorsque tu ouvres ton "etatImpr" il y a déjà une source de donnée défini (en principe), ce n'est pas en créant un recordset "Avoir" (surtout sans l'affecter à l'état) que tu pourras le changer.
    d'ailleurs les champs de l'état étant crée en fonction de la source il n'est pas recommandé de la modifier, sauf en pleine connaissance de cause.

    dans l'état tu retrouves dans 'ajouter des champs existants' (access 2007) l'ensemble des champs disponibles dans ton état sur lequel tu peux appliquer ton filtre.
    si tu avais "Avoir" comme source de ton état:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.OpenReport "etaImpr", acViewPreview, , "[NumNote] = " & CStr(lstNotes)
    tu peux aussi faire des essais préalable: "[NumNote]=1"
    mais puisque tu as Requête3, assure toi qu'il y a bien NumNote parmi ses champs.
    et si tu tiens à mentionner la source de la table: mentionne celle qui est présente dans la source de ton état...
    Merci de m'avoir signalé ces erreurs. Le truc c'est que c'est la première fois que j'utilise un état, donc je tâtonne
    Alors la source de mon état est bien "Requête 3" qui contient :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT N.NumNote, N.DateNote, C.NumContrat, C.DateEnregContrat, Cl.NumCli, Cl.NomCli, C.DateEffetContrat, C.NatureContrat, V.NomVendeur, S.PrenomEmploye, M.LibMotif, A.NumAgence, M.NumMotif, S.TelEmploye, S.NomEmploye, A.NomAgence, N.ComNote
    FROM NOTES AS N, CONTRAT AS C, CLIENT AS Cl, AGENCE AS A, VENDEUR AS V, SERV_ASSU AS S, MOTIF AS M, Avoir AS Av
    WHERE C.NumContrat=N.NumContrat And C.NumCli=Cl.NumCli And C.NumAgence=A.NumAgence And C.NumVendeur=V.NumVendeur And N.NumEmploye=S.NumEmploye And M.NumMotif=Av.NumMotif And Av.NumNote=N.NumNote;
    Et donc les contrôles de mon état sont remplis avec un truc du genre :
    Requête 3.NomChamp
    Est-ce que je suis sur la bonne voie ?
    Parce qu'en mettant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.OpenReport "etaImpr", acViewPreview, , "[NumNote] = " & CStr(lstNotes)
    Access me dit que le champ spécifié '[NumNote]' peut lister plusieurs tables listées dans la clause FROM de mon instruction SQL
    Du coup, j'ai ajouté la table devant le nom de mon champ :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.OpenReport "etaImpr", acViewPreview, , "[Avoir].[NumNote] = " & CStr(lstNotes)
    Mais dans ce cas, Access me demande la valeur de [Avoir].[NumNote]

    Citation Envoyé par Jeannot45 Voir le message
    Merci Vodiem pour ce coup de main

    P.S : A propos d'autre chose, tu trouveras dans ma signature un lien vers le tuto de planning (partie 1) qui est maintenant en ligne. je ne sais pas si tu as pu résoudre ton problème d'affichage.

    Bonne journée
    J'avais déjà commencer à regarder
    Merci pour ta base

    P.S : ma nouvelle version d'Access est 2002 (depuis hier)
    Si ma réponse vous a été utile pensez à voter Pour

    Avant de poster sur le forum Access :
    FAQ > SOURCES > COURS > FORUM > GOOGLE
    Pas de question par MP ou je mords


  11. #11
    Expert confirmé
    Avatar de vodiem
    Homme Profil pro
    Vivre
    Inscrit en
    Avril 2006
    Messages
    2 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Vivre
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2006
    Messages : 2 895
    Points : 4 325
    Points
    4 325
    Par défaut
    Citation Envoyé par azertix
    Le truc c'est que c'est la première fois que j'utilise un état, donc je tâtonne
    dis toi qu'il y a si peu de différence entre un formulaire et un état que tu peux penser que c'est la même chose. d'ailleurs pour le système ce n'est qu'une différence de driver de sortie: écran ou papier.

    en regardant mieux ton sql, oulà...
    tu crées une sacré cardinalité d'enregistrements: utilise les jointures.
    l'ambiguïté viens que NumNote peut provenir de deux tables.
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    WHERE ... AND Av.NumNote=N.NumNote;
    je n'ai pas regardé de plus près le mécanisme qu'emploie access pour traiter cela mais pour expliquer ce message, je ne me tromperais pas (je pense) en te disant que cette requete est reprise dans ton état tel quel (requete3 n'est pas "reconnu" comme une table) et donc ta parti filtre where ... va être remplacé par celui que tu mets en code à l'ouverture:
    donc tu imagines bien les conséquences...
    même si:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    "N.NumNote = " & CStr(lstNotes)
    devrait (?) marché cela devrais te créer un pb: tu n'as plus ta simili jointure.
    il faudrait donc rajouter tout le critère where en plus (si tu ne fait pas de vrais jointures).

    au pire tu ouvre requete3 et tu rajoute dans le qbe sur NumNote un critère: CStr(Forms!MonForm!lstNotes) tu recopie le sql généré que tu mets en source de ton état que tu ouvres simplement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DoCmd.OpenReport "etaImpr", acViewPreview

  12. #12
    Membre éprouvé Avatar de azertix
    Homme Profil pro
    Technicien d'assistance informatique
    Inscrit en
    Juin 2007
    Messages
    958
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien d'assistance informatique

    Informations forums :
    Inscription : Juin 2007
    Messages : 958
    Points : 937
    Points
    937
    Par défaut
    Parfait ! J'ai opté pour ta deuxième proposition, et ça fonctionne au poil
    En plus j'ai bien compris le fonctionement des états, à présent


    P.S : j'ai une question un peu plus compliquée pour mon état : je voudrais cocher des checkbox dans mon état en fonction des différents éléments sélectionnés d'une zone de liste à sélection multiple de mon formulaire, mais je sais pas si ça rentre dans le cadre de ce topic, donc je vais en créer un nouveau

    Edit : C'est créé !
    http://www.developpez.net/forums/sho...d.php?t=564346
    Si ma réponse vous a été utile pensez à voter Pour

    Avant de poster sur le forum Access :
    FAQ > SOURCES > COURS > FORUM > GOOGLE
    Pas de question par MP ou je mords


+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [AC-2010] Afficher des images dans un état selon une condition
    Par Benez dans le forum VBA Access
    Réponses: 6
    Dernier message: 31/07/2012, 15h13
  2. Réponses: 2
    Dernier message: 07/10/2009, 17h01
  3. Réponses: 1
    Dernier message: 20/02/2009, 13h57
  4. Réponses: 12
    Dernier message: 06/08/2007, 07h46
  5. afficher des photos dans un état.
    Par jeck dans le forum IHM
    Réponses: 4
    Dernier message: 02/06/2006, 15h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo