0

Je crée un modèle db pour la génération de factures de location. La facture comprend N périodes de réservation.DB Schema: Modèle de prix versionné par rapport aux données relatives aux factures

Chaque réservation fait partie d'un modèle de prix. Un modèle de prix est un ensemble de règles qui déterminent un prix final (prix de base + prix de la saison + quantité discout + ...). Cela signifie que le prix final pour les N réservations dans une facture peut être un calcul complexe, et bien sûr je veux garder une trace de chaque aspect du calcul du prix final pour l'examen ultérieur d'une facture.

Le problème est qu'un modèle de prix peut changer dans le futur. Donc, lors de la génération de facture, il y a deux possibilités:

  • (a) Ne jamais modifier un modèle de prix. Il suffit de le rendre immuable en le versionnant et de se référer à une version concrète d'une facture. (B) Inscrire toutes les informations sur les prix, les remises et les extras dans la facture. Cela signifierait beaucoup de données, car une facture contient N réservations qui peuvent être en partie dans la fourchette d'un prix de saison. Fondamentalement, je décomposerais chaque réservation dans ses jours et pour chaque jour j'aurais N lignes calculant le prix de base, les réductions et les frais supplémentaires.

modèle de table possible:

Invoice 
    id: int 

InvoiceBooking   # Each booking. One invoice has N bookings 
    id: int 
    invoiceId: int 
    (other data, e.g. guest information) 

InvoiceBookingDay  # Days of a booking. Each booking has N days 
    id: int 
    invoiceBookingId: id 
    date: date 

InvoiceBookingDayPriceItem # Concrete discounts, etc. One days has many items 
    id: int 
    invoiceBookingDayId: int 
    price: decimal 
    title: string 

Ma question est, de quelle manière dois-je préfère et pourquoi.

Mes considérations:

  • Avec la solution (a), seraient recalculés la facture en utilisant les informations du modèle de prix chaque fois que les données sont visualisées. Je n'aime pas ça, car les algorithmes peuvent changer. Cela ne semble pas naturel pour la nature «en lecture seule» d'une facture. La gestion des versions de modèles de prix n'est pas non plus une tâche triviale et l'utilisateur doit connaître le concept de version, ce qui ajoute de la complexité aux applications. Avec la solution (b), je génère un tas de données imbriquées et ajoute beaucoup de complexité au schéma.

De quelle façon préférez-vous? Est-ce que je manque quelque chose?

Merci

Répondre

1

Que diriez-vous et B?

Il n'est pas recommandé de recalculer un composant d'une facture, en particulier si le composant a été imprimé. Les détails de la facture et de la facture doivent être immuables et vous devriez pouvoir les reproduire sans avoir à les recalculer.

Si jamais vous avez un problème avec comprendre comment vous avez obtenu un certain montant, ou s'il y a un bogue dans votre programme, vous serez heureux que vous avez les détails, surtout si les calculs sont complexes.

En outre, il est recommandé de conserver un historique de vos modèles de tarification afin de pouvoir valider votre prix. Vous pouvez rendre ceci simple à vos utilisateurs. Ils n'ont pas besoin de voir l'historique - mais vous devez enregistrer leurs modifications dans le journal de l'historique.

2

Il existe une troisième option que je recommande. Je l'appelle le versionnage temporel (temporel) et la disposition de la table est vraiment très simple. Vous ne décrivez pas vos données de tarification, donc je vais vous montrer un exemple simple.

Table: DailyPricing 
ID EffDate  Price ... 
A 01/01/2015 17.50 ... 
B 01/01/2015 20.00 ... 
C 01/01/2015 22.50 ... 
B 01/01/2016 19.50 ... 
C 07/01/2016 24.00 ... 

Cela montre que les trois barèmes de prix (A, B et C représentent un peu quelle que soit la méthode utilisée pour distinguer entre les niveaux de prix) ont reçu un prix le 1er janvier 2015. Le 1er janvier 2016, le prix du plan B a été réduit. En juillet, le prix du plan C a été augmenté.

Pour obtenir le prix actuel d'un plan, la requête est la suivante:

select dp.Price 
from DailyPricing dp 
where dp.ID = 'A' 
    and dp.Effdate =(
     select Max(dp2.EffDate) 
     from DailyPricing dp2 
     where dp2.ID = dp.ID 
      and dp2.EffDate >= :DateOfInterest); 

La variable DateOfInterest serait chargée de la date/heure. Cette requête renvoie le seul prix actuellement en vigueur. Dans ce cas, le prix fixé le 1er janvier 2015 comme cela n'a jamais changé depuis son entrée en vigueur. Si la recherche avait porté sur le plan B, le prix fixé le 1er janvier 2016 aurait été retourné et pour le plan C, le prix fixé le 1er juillet 2016. Il s'agit des derniers prix établis pour chaque plan; c'est-à-dire, les prix actuels.

Une telle requête serait plus probablement dans une jointure avec probablement la table de facture afin que vous puissiez effectuer le calcul de prix.

select ... 
from Invoices i 
join DailyPricing dp 
    on dp.ID = i.ID 
    and dp.Effdate =(
     select Max(dp2.EffDate) 
     from DailyPricing dp2 
     where dp2.ID = dp.ID 
      and dp2.EffDate >= i.InvoiceDate) 
where i.ID = 1234; 

Ceci est un peu plus complexe qu'une simple requête, mais vous demandez des données plus complexes (ou plutôt une vision plus complexe des données). Cependant, ce calcul n'est probablement exécuté qu'une seule fois et le prix final est stocké dans les données de facturation ou ailleurs.

Il ne sera calculé à nouveau que si le client a apporté quelques modifications ou si vous avez subi une vérification, en vérifiant à nouveau le calcul pour en vérifier l'exactitude.

Notez quelque chose, cependant, qui est subtile mais très important. Si la requête ci-dessus était en cours d'exécution pour une facture qui venait d'être créée, l'InvoiceDate serait la date actuelle et le prix retourné serait le prix actuel. Si, toutefois, la requête était exécutée comme une vérification sur une facture datant de deux ans, l'InvoiceDate serait il y a deux ans et le prix retourné serait le prix en vigueur il y a deux ans. En d'autres termes, la requête pour retourner les données actuelles et la requête pour retourner les données passées est la même requête. En effet, les données actuelles et les données antérieures restent dans la même table, différenciées uniquement par la date à laquelle les données sont prises en compte. Ceci, je pense, est à propos de la solution la plus simple à ce que vous voulez faire.