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

Schéma Discussion :

Comprehension produit facture, 1n 0n [MCD]


Sujet :

Schéma

  1. #1
    Membre régulier Avatar de Mika2008
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    176
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 176
    Points : 71
    Points
    71
    Par défaut Comprehension produit facture, 1n 0n
    Bonjour,

    j'ai ce mcd :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    [ Factures ]---1,n---(contient)---0,n---[ produits ]
    Factures (id_fact,num_fact,date_fact)
    Produits(id_produit,NomProduit)
    Donc une facture contient 1 ou plusieurs produit et
    un produit peut être contenu dans aucune ou plusieurs facture

    Ce qui donne comme MPD :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    [ Factures ]---1,n---[contient]---0,n---[ produits ]
    Factures (id_fact,num_fact,date_fact)
    Produits(id_produit,NomProduit)
    contient(id_fact,id_produit)
    ce que je ne comprend pas, dans ce petit exemple, c'est comment on gère la quantité de produit dans une facture
    ne faut il pas que je rajoute un champ dans contient, qui gère la quantité?
    et si dans une facture j'achète deux produits, c'est géré comment?

    merci d'avance à la personne qui pourras m'expliquer

  2. #2
    Membre averti
    Avatar de wafiwafi
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    500
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 500
    Points : 328
    Points
    328
    Par défaut Elle est gérée par la classe contient
    Elle est gérée par la classe contient ayant comme attributs id_fact et id_produit. On peut penser à l'implémentation d'une table regroupant tous les couples id_fact et id_produit. Du moment ou on a cette dernière, il est facile d'avoir toute information sur les quantités.
    J'espère avoir été clair.
    L'immortalité existe, elle s'appelle connaissance

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Bonsoir,

    Vous pourriez décrire votre facture comme un ensemble de "lignes" associées à une commande/prestation. Chaque ligne étant la référence à produit, description, quantité, éventuellement remise et prix vendu.

    Les dernières informations étant liées à la commande associée à la facture.

    Catalogue produit, prix, remise, commande et facture sont des entités ayant des cycles de vie et des propriétaires en principe différents. Pire ces entités muent: une facture payée rentre dans un historique et doit être conservée pendant quelques années.

    Représenter la ligne à facturer dans un SGDB n'est pas si trivial: si la référence au produit est un FK vers le catalogue produit, on induit une relation 'forte' entre le PK de la table 'catalogue' et l'identifiant 'métier' du produit (chiffres/lettres +/- segmenté). Il est parfois préférable de dénormaliser i.e. utiliser un id métier.

    Bon courage
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Membre averti
    Avatar de wafiwafi
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    500
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 500
    Points : 328
    Points
    328
    Par défaut c'est une bonne solution
    Oui c'est une bonne solution. Néanmoins, j'avais compris d'émettre une réponse simplifiée sur la question posée. Cela risque d'embrouiller notre ami. Je pense qu'il essaye de comprendre déjà ou se situe la représentation de la multiplicité entre factures et produits.
    Je me trompe peut être. Que pensez vous de la réponse que j'ai émise?
    Merci
    L'immortalité existe, elle s'appelle connaissance

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Citation Envoyé par wafiwafi Voir le message
    Je pense qu'il essaye de comprendre déjà ou se situe la représentation de la multiplicité entre factures et produits.
    Je me trompe peut être. Que pensez vous de la réponse que j'ai émise?
    Merci
    Elle est techniquement correcte s'il s'agit de traduire une relation *---* par une association. Mais rend elle compte de la relation métier entre factures et produits?
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Membre averti
    Avatar de wafiwafi
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    500
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 500
    Points : 328
    Points
    328
    Par défaut c'est vrai. Elle ne peut rendre compte
    Bonjour,
    c'est vrai. Elle ne peut rendre compte de la relation métier entre factures et produits. Mais avec un choix judicieux des méthodes ou fonctions à implémenter, on peut satisfaire cette dernière selon un cahier de charge bien défini.
    bien à vous
    L'immortalité existe, elle s'appelle connaissance

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Citation Envoyé par wafiwafi Voir le message
    Bonjour,
    c'est vrai. Elle ne peut rendre compte de la relation métier entre factures et produits. Mais avec un choix judicieux des méthodes ou fonctions à implémenter, on peut satisfaire cette dernière selon un cahier de charge bien défini.
    bien à vous
    Certes mais le modèle de donnée est souvent plus difficile à faire évoluer que les applications qui s'appuient dessus. Son design mérite d'être secoué pour se conforter de sa robustesse et s'assurer que les temps de réponses des traitements clés seront acceptables suivant différent scénarii d'évolution.

    Des arbitrages pas toujours simple entre ce qui sera pris en charge via des triggers et/ou procédures stockés ou codé dans l'application sont aussi à faire.

    Vous pouvez avoir une approche inverse....
    Tout est objet et la base de donnée n'est là que pour assurer des fonctions de persistance. On n'utilise ses fonctionnalités que quand on ne peut faire autrement.
    Dans ce cas, vous pouvez si vous n'y prenez garde avoir un couplage fort entre 'la persistance' et l'ORM choisi pour la réaliser....
    Certaines évolutions risquent d'être pénibles à réaliser.

    Le point d'équilibre est à trouver entre:
    - Un modèle de données assez stable ou n'évoluant qu'à la marge.
    - Une bonne flexibilité pour les applications réalisées au dessus (avec un ORM mais contraint par le modèle de données).
    -W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  8. #8
    Membre averti
    Avatar de wafiwafi
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    500
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 500
    Points : 328
    Points
    328
    Par défaut C'est tellement vrai
    C'est tellement vrai! il faut être en plein chantier pour s'en rendre compte.
    C'est une très bonne analyse qui laisse beaucoup à réfléchir.
    L'immortalité existe, elle s'appelle connaissance

  9. #9
    Membre régulier Avatar de Mika2008
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    176
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 176
    Points : 71
    Points
    71
    Par défaut
    Bonjour,
    et merci de vos réponse,
    j'avoue ne pas avoir très bien compris vos remarque :

    Pour wafiwafi :
    Si je comprend bien,
    dans mon MPD(j'ai rajouter un champ "quantite" dans contient):
    [ Factures ]---1,n---[contient]---0,n---[ produits ]
    Factures (id_fact,num_fact,date_fact)
    Produits(id_produit,NomProduit)
    contient(id_fact,id_produit,quantite)
    si j'ai dans une facture plusieurs produit, j'aurais dans la table contient
    plusieur id_fact identique, avec des produits différent?
    exemple si dans facture j'ai :
    FACTURES
    id_fact | num_fact | date_fact
    1 | 200807001 | 2008/07/02
    2 | 200807002 | 2008/07/02
    3 | 200807003 | 2008/07/02

    Produits
    id_produit | NomProduit
    101 | Produit_A
    202 | Produit_B
    303 | Produit_C

    Donc contient auras :
    contient
    id_fact | id_produit | quantite
    1 | 101 | 5
    1 | 303 | 4
    2 | 202 | 4
    3 | 303 | 4
    3 | 101 | 4
    Donc cela veut dire que pour la facture 1 j'ai acheter deux produits avec des quantité 5 pour le premier et 4 pour le deuxiéme?



    Pour wiztricks :

    Pour votre résonne ment, il faudra que je rajoute une entité commande :
    [ Factures ]---1,n---[contient]---1,1---[commande]---1,n---(reference)----0,n--[ produits ]
    et dans commande j'aurais la quantité, c'est intéressante, mais je ne vois ce que sa apporte de plus par rapport à la première méthode?

    merci d'avance

  10. #10
    Membre averti
    Avatar de wafiwafi
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    500
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 500
    Points : 328
    Points
    328
    Par défaut comme a dit wiztricks de façon générale,
    Bonjour,
    comme a dit wiztricks de façon générale, il est pertinent de bien analyser son modèle pour mieux le maitriser tant à la conception qu'à l'implémentation.
    La présence d'une classe commande me parait indispensable. Imaginer un client qui commande et qui annule par la suite ou tout simplement modifie le contenu de cette dernière. Au stade d'une commande l'objet issu de la classe facture n'est même pas encore né. C'est quand tu t'apprête à livrer qu'il va voir le jour et interagir avec les autres objets existant selon ton modèle et tes applications qui entrent en scène. Ce dernière mourra peut être quand tu clôturera l'exercice de l'année.
    J'essaye d'être simple dans mes explications.
    Bien à vous
    L'immortalité existe, elle s'appelle connaissance

  11. #11
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Pour wiztricks :

    Pour votre résonne ment, il faudra que je rajoute une entité commande :
    Citation:
    [ Factures ]---1,n---[contient]---1,1---[commande]---1,n---(reference)----0,n--[ produits ]
    et dans commande j'aurais la quantité, c'est intéressante, mais je ne vois ce que sa apporte de plus par rapport à la première méthode?

    merci d'avance
    L'idée de base est que commandes et factures sont des objets similaires pour lesquels la ligne { ID commande, état, référence produit, quantité } change d'état (commandé, livré, payé).
    Ce modèle est peut être trop 'zen' pour rendre compte des aspects métiers mais c'est l'idée.

    Vous n'avez donc, à priori, rien à ajouter mais beaucoup à enlever.
    -W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  12. #12
    Membre averti
    Avatar de wafiwafi
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    500
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 500
    Points : 328
    Points
    328
    Par défaut Donc pour toi wiztricks une seule classe
    Donc pour toi wiztricks une seule classe pour commande et facture. C'est par un changement d'état que commande se transforme en facture. Ce n'est pas mal. On aura une classe de moins et donc pas mal de messages en moins.
    rien à dire.
    L'immortalité existe, elle s'appelle connaissance

  13. #13
    Membre chevronné
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Août 2007
    Messages
    797
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Août 2007
    Messages : 797
    Points : 2 060
    Points
    2 060
    Par défaut
    Bonjour,

    Je rappellerai simplement quelques réalités (si toutefois des étudiants lisent ces lignes, ça pourra leur éviter bien des désillusions).

    Citation Envoyé par wiztricks Voir le message
    L'idée de base est que commandes et factures sont des objets similaires pour lesquels la ligne { ID commande, état, référence produit, quantité } change d'état (commandé, livré, payé).
    Citation Envoyé par wafiwafi
    Donc pour toi wiztricks une seule classe pour commande et facture. C'est par un changement d'état que commande se transforme en facture. Ce n'est pas mal. On aura une classe de moins et donc pas mal de messages en moins.
    Dans cet échange, vous vous mettez à la place de la maîtrise d'ouvrage, du concepteur, du développeur et du DBA tout à la fois. Vous êtes multi-casquettes, quoi ! Ce n'est pas toujours le cas dans une entreprise.

    Si certaines entreprises adopteraient sans broncher cette vision des choses dans laquelle 1 facture = 1 commande qui change d'état, dans d'autres vous seriez immédiatement cloué au pilori pour :
    1) avoir proféré de telles énormités,
    2) avoir empiété sur le domaine réservé de la maîtrise d'ouvrage (certaines MOA n'ont pas du tout le sens de l'humour quand on touche au métier)


    Donc, attention à ne pas confondre modélisation et cuisine ; on ne peut pas toujours faire "à sa sauce".
    N'oubliez pas de consulter les Cours Merise et la F.A.Q. Merise
    _______________________________________________________

    Les Règles du Club Developpez.com
    Vous avez votre réponse ? Merci de cliquer sur

  14. #14
    Membre averti
    Avatar de wafiwafi
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    500
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 500
    Points : 328
    Points
    328
    Par défaut Je comprend le principe sur lequel
    Bonjour,
    Je comprends le principe sur lequel tu te bases et je suis entièrement daccord qu'il faut éviter toute interférence dans le projet. Par contre, je ne vois pas le tort dans cette discussion. il ya tout de même un truc qui m'échape! je ne vois pas de diversification de casquettes puisqu'on est resté dans le domaine de a conception. J'ai relu la discussion et en aucun endroit je n'ai trouvé de dires concernant des solutions d'implémentation. néanmoins, c'est vrai qu'on a parlé de tables mais c'est une question d'habitude puisque quand on fait du merise, on pense automatiquement aux tables. Aucune solution d'implémentation n'a été fournie.
    On est tout de même resté concepteur avec un choix de solution; c'est l'objectif de la conception elle même puisqu'elle consiste à chercher des solutions et choisir les meilleures.
    Toute solution doit être en accord avec la MOA. J'insiste en disant si accord est, pourquoi s'interdire à l'adopter. Donc, il n'a aucune interférence avec les acteurs du métier. On n'impose rien!
    En résumé, si je ne décide pas à la place de la MOA et je n'evoque pas de solutions d'implémentation, je ne comprend pas donc le dernier message.
    Tu veux certainement dire quelque chose que je ne comprends pas. Merci d'éclairer mes lanternes.
    L'immortalité existe, elle s'appelle connaissance

  15. #15
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Dans la THEORIE, on pourrait effectivement imaginer le circuit :
    1 Demande de prix pour plusieurs produits ==> 1 Devis pour les produits demandés ==> 1 Commande des produits proposés ==> 1 livraison des produits commandés ==> 1 facture des produits livrés.

    Dans ce schéma idéal, une entité (ou classe selon l'affinité du concepteur avec le MCD Merise ou le diagramme de classes UML) qui change d'état peut suffire.

    Dans la REALITE, on a plutôt :
    1 Demande de prix pour plusieurs produits avec des variantes ==> 1 devis pour les produits et variantes demandés ==> X modifications du devis ==> 1 ou plusieurs commande(s) pour les produits choisis, avec des remises commerciales sur certains produits ou au montant global de la facture ==> 1 ou plusieurs livraisons selon le choix du client, la disponibilité des produits, les incidents de production... ==> 1 ou plusieurs factures correspondant aux diverses livraisons, lesquelles sont parfois remises en cause par le client en raison de problèmes rencontrés, de facturation anticipée, de contestations sur la qualité des produits reçus...

    Je serais donc plutôt enclin à séparer les concepts :
    - devis
    - commande
    - livraison
    - facture

    Et dans ce cas, ce qui peut sembler être une redondance de données - la recopie des quantités et prix unitaires des produits d'une entité à l'autre - n'est en fait qu'un groupe de données à conserver pour chaque étape.

    Exemple avec 1 produit...
    1) Mon client me demande un prix pour 18 trucs ;
    2) Je lui fais un devis pour 18 trucs à 150 euros mais je lui précise dans le texte d'accompagnement que s'il m'en commande 20, il aura une remise de 15% sur le prix unitaire.
    3) Le client en commande 20 avec donc un prix remisé.
    4) Je ne peux lui en livrer que 15 tout de suite et les 5 derniers dans un mois. Il y a donc deux livraisons.
    5) Je lui facture d'abord les 15 premiers (avec le prix remisé) puis les 5 dernier (avec le prix remisé)
    6) Il y a un problème de qualité sur l'un des 5 derniers et le client râle, refuse la facture, demande un dédomagement commercial.
    7) Je lui livre un nouveau truc pour remplacer le défectueux, soit une livraison supplémentaire et un retour de produit à enregistrer.
    8) Je lui fais un avoir de 150 euros.

    Avec une seule entité dans mon modèle, je fais comment ?

    On voit ici qu'on peut avoir besoin de la structure suivante :
    Client (Cli_Id, Cli_Nom...)
    Produit (Prd_Id, Prd_Nom, Prd_Reference, Prd_PrixHT, Prd_IdCodeTVA...)

    Devis (Dev_Id, Dev_Reference, Dev_IdClient, Dev_DateCreation, Dev_DateModification...)
    LigneDevis (LD_IdDevis, LD_IdProduit, LD_Quantite, LD_PrixUnitaireHT, LD_RemiseUnitaire...)

    Commande (Cmd_Id, Cmd_Reference, Cmd_IdClient, Cmd_IdDevis, Cmd_TotalHT, Cmd_RemiseGenerale...)
    LigneCommande (LC_Id, LC_IdCommande, LC_IdProduit, LC_Quantite, LC_PrixUnitaireHT, LC_IdCodeTVA, LC_RemiseUnitaire...)

    Livraison (Liv_Id, Liv_IdCommande, Liv_EtatLivraison...)
    LigneLivraison (LL_Id, LL_IdLivraison, LL_IdLigneCommande, LL_QuantiteLivree)

    Facture (Fac_Id, Fac_Référence, Fac_IdLivraison, Fac_TotalHT, Fac_RemiseGenerale...)
    LigneFacture (LF_IdFacture, LF_IdLigneLivraison, LF_QuantiteFacturée, LF_PrixUnitaireHT, LF_RemiseUnitaire, LF_IdCodeTVA...)

    Avoir (Av_Id, Av_IdCommande, Av_Montant...)

    C'est sans doute à peaufiner mais c'est l'idée générale.

    En résumé : séparer les concepts évitera d'éventuels problèmes futurs.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  16. #16
    Membre averti
    Avatar de wafiwafi
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    500
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 500
    Points : 328
    Points
    328
    Par défaut Je ne peux être qu'en accord avec toi
    Je ne peux être qu'en accord avec toi. Le choix de solution d'entité distinctes en ce qui concerne commande et facture est très bien défendu et surtout justifié. Je ne peux que m'incliner dans la mesure ou la réalité du terrain est parfois une grande contrainte en dépit de simplification du modèle. Un client qui accepterait la solution du changement d'état se rendra compte qu'il faudrait faire autrement.

    Néanmoins, la discussion est bien restée auparavant dans le domaine de la conception et il n'y a pas eu de mélange!
    L'immortalité existe, elle s'appelle connaissance

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

Discussions similaires

  1. Ajouter le poids du produit dans les lignes de la facture
    Par Onimanta dans le forum Odoo (ex-OpenERP)
    Réponses: 10
    Dernier message: 27/12/2015, 08h46
  2. Création formulaire de Facture avec produits multiples
    Par Sébastien1609 dans le forum IHM
    Réponses: 11
    Dernier message: 13/06/2013, 14h45
  3. plusieurs produits pour une facture
    Par enrone dans le forum IHM
    Réponses: 18
    Dernier message: 14/05/2013, 17h03
  4. rajouter l'origine des produits sur les factures
    Par Bob2175 dans le forum Oracle
    Réponses: 1
    Dernier message: 21/11/2006, 19h03
  5. imprimer une facture avec liste de produits variables
    Par ouldfella dans le forum Delphi
    Réponses: 4
    Dernier message: 30/07/2006, 23h10

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