{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE QuantifiedConstraints #-} {-# LANGUAGE UndecidableInstances #-} module Literate.Invoice where import Country qualified import Literate.Accounting.Amount import Literate.Accounting.Quantity import Literate.Accounting.Unit import Literate.Document qualified as Doc import Literate.Document.HTML qualified as HTML import Literate.Organization import Literate.Prelude import Literate.Time data InvoiceId entId = InvoiceId { invoiceIdRecipient :: entId , invoiceIdType :: InvoiceType , invoiceIdCount :: Natural } deriving (Eq, Ord, Show, Generic, NFData) instance ( GetOrganization entId , GetEntity entId , Doc.ToInline entId ) => Doc.ToInline (InvoiceId entId) where toInline i = [ "org" , i & invoiceIdRecipient & getOrganization & orgEntity & getEntity & entityId & Doc.toInline , case i & invoiceIdType of InvoiceTypeProForma -> "pro-forma" InvoiceTypeSale -> "sale" InvoiceTypeVoucher -> "voucher" , i & invoiceIdCount & show & Doc.toInline ] & Doc.Inlines type Invoices entId = Map (InvoiceId entId) (Invoice entId) type InvoiceAction = [Text] type InvoiceScope = [Text] data Invoice entId = Invoice { invoiceEmittedOn :: LocalTime , invoiceOrders :: [Doc.Inline] , invoicePaymentDueBefore :: LocalTime , invoiceIssuer :: entId , invoiceRecipient :: entId , -- , invoiceItems :: [InvoiceItem (UnitName "€" :/: UnitName "h") (UnitName "h")] invoiceRates :: Map InvoiceAction (Amount 100 (UnitName "€" :/: UnitName "h")) , invoiceMentions :: [InvoiceMention] , invoiceWorks :: [Work] } deriving (Eq, Show) invoice :: Enum entId => Invoice entId invoice = Invoice { invoiceEmittedOn = "2000-01-01" , invoiceOrders = [] , invoicePaymentDueBefore = "2000-01-31" , invoiceIssuer = toEnum 0 , invoiceRecipient = toEnum 0 , invoiceRates = [] , invoiceMentions = [] , invoiceWorks = [] } data Work = Work { workDescription :: Doc.Inline , workDate :: LocalTime , workDuration :: Amount 100 (UnitName "h") , workAction :: [Text] , workScope :: [Text] , workReferences :: [URL] } deriving (Eq, Show) data InvoiceType = InvoiceTypeSale | InvoiceTypeProForma | InvoiceTypeVoucher deriving (Eq, Ord, Show, Generic, NFData) data InvoiceMention = InvoiceMentionTVANonApplicable | InvoiceMentionIndemnitéForfaitaire | InvoiceMentionIndemnitéTaux (Amount 100 (UnitName "%")) deriving (Eq, Ord, Show, Generic, NFData) data InvoiceItem rate qty = InvoiceItem { invoiceItemScope :: [Text] , invoiceItemAction :: [Text] , invoiceItemType :: InvoiceItemType , invoiceItemPeriod :: Period , invoiceItemRate :: Amount 100 rate , invoiceItemQuantity :: Amount 100 qty } deriving (Eq, Show) type Euro = Amount 100 (UnitName "€") invoiceItemTotal :: InvoiceItem rate qty -> Euro invoiceItemTotal InvoiceItem{..} = let (res, _actualFrac) = invoiceItemRate & amountQuantity & fraction (invoiceItemQuantity & amountQuantity & quantityToRatio) in Amount res invoiceItem = InvoiceItem { invoiceItemScope = [] , invoiceItemAction = [] , invoiceItemType = InvoiceItemTypeItem , invoiceItemPeriod = Period{periodBeginning = "2000-01-01", periodEnd = "2000-01-01"} , invoiceItemRate = 0 , invoiceItemQuantity = 0 } data InvoiceItemType = InvoiceItemTypeItem | InvoiceItemTypeService deriving (Eq, Ord, Show) data Period = Period { periodBeginning :: LocalTime , periodEnd :: LocalTime } deriving (Eq, Ord, Show, Generic, NFData)