]> Git — Sourcephile - tmp/julm/literate-invoice.git/blob - src/Literate/Invoice.hs
maint/correctness(Entity): use sum type for EntityId
[tmp/julm/literate-invoice.git] / src / Literate / Invoice.hs
1 {-# LANGUAGE DeriveAnyClass #-}
2 {-# LANGUAGE OverloadedLists #-}
3 {-# LANGUAGE QuantifiedConstraints #-}
4 {-# LANGUAGE UndecidableInstances #-}
5
6 module Literate.Invoice where
7
8 import Country qualified
9 import Literate.Accounting.Amount
10 import Literate.Accounting.Quantity
11 import Literate.Accounting.Unit
12 import Literate.Document qualified as Doc
13 import Literate.Document.HTML qualified as HTML
14 import Literate.Organization
15 import Literate.Prelude
16 import Literate.Time
17
18 data InvoiceId entId = InvoiceId
19 { invoiceIdRecipient :: entId
20 , invoiceIdType :: InvoiceType
21 , invoiceIdCount :: Natural
22 }
23 deriving (Eq, Ord, Show, Generic, NFData)
24 instance
25 ( GetOrganization entId
26 , GetEntity entId
27 , Doc.ToInline entId
28 ) =>
29 Doc.ToInline (InvoiceId entId)
30 where
31 toInline i =
32 [ "org"
33 , i
34 & invoiceIdRecipient
35 & getOrganization
36 & orgEntity
37 & getEntity
38 & entityId
39 & Doc.toInline
40 , case i & invoiceIdType of
41 InvoiceTypeProForma -> "pro-forma"
42 InvoiceTypeSale -> "sale"
43 InvoiceTypeVoucher -> "voucher"
44 , i & invoiceIdCount & show & Doc.toInline
45 ]
46 & Doc.Inlines
47
48 type Invoices entId = Map (InvoiceId entId) (Invoice entId)
49 type InvoiceAction = [Text]
50 type InvoiceScope = [Text]
51
52 data Invoice entId = Invoice
53 { invoiceEmittedOn :: LocalTime
54 , invoiceOrders :: [Doc.Inline]
55 , invoicePaymentDueBefore :: LocalTime
56 , invoiceIssuer :: entId
57 , invoiceRecipient :: entId
58 , -- , invoiceItems :: [InvoiceItem (UnitName "€" :/: UnitName "h") (UnitName "h")]
59 invoiceRates :: Map InvoiceAction (Amount 100 (UnitName "€" :/: UnitName "h"))
60 , invoiceMentions :: [InvoiceMention]
61 , invoiceWorks :: [Work]
62 }
63 deriving (Eq, Show)
64
65 invoice :: Enum entId => Invoice entId
66 invoice =
67 Invoice
68 { invoiceEmittedOn = "2000-01-01"
69 , invoiceOrders = []
70 , invoicePaymentDueBefore = "2000-01-31"
71 , invoiceIssuer = toEnum 0
72 , invoiceRecipient = toEnum 0
73 , invoiceRates = []
74 , invoiceMentions = []
75 , invoiceWorks = []
76 }
77 data Work = Work
78 { workDescription :: Doc.Inline
79 , workDate :: LocalTime
80 , workDuration :: Amount 100 (UnitName "h")
81 , workAction :: [Text]
82 , workScope :: [Text]
83 , workReferences :: [URL]
84 }
85 deriving (Eq, Show)
86 data InvoiceType
87 = InvoiceTypeSale
88 | InvoiceTypeProForma
89 | InvoiceTypeVoucher
90 deriving (Eq, Ord, Show, Generic, NFData)
91 data InvoiceMention
92 = InvoiceMentionTVANonApplicable
93 | InvoiceMentionIndemnitéForfaitaire
94 | InvoiceMentionIndemnitéTaux (Amount 100 (UnitName "%"))
95 deriving (Eq, Ord, Show, Generic, NFData)
96
97 data InvoiceItem rate qty = InvoiceItem
98 { invoiceItemScope :: [Text]
99 , invoiceItemAction :: [Text]
100 , invoiceItemType :: InvoiceItemType
101 , invoiceItemPeriod :: Period
102 , invoiceItemRate :: Amount 100 rate
103 , invoiceItemQuantity :: Amount 100 qty
104 }
105 deriving (Eq, Show)
106 type Euro = Amount 100 (UnitName "€")
107
108 invoiceItemTotal :: InvoiceItem rate qty -> Euro
109 invoiceItemTotal InvoiceItem{..} =
110 let (res, _actualFrac) =
111 invoiceItemRate
112 & amountQuantity
113 & fraction (invoiceItemQuantity & amountQuantity & quantityToRatio)
114 in Amount res
115 invoiceItem =
116 InvoiceItem
117 { invoiceItemScope = []
118 , invoiceItemAction = []
119 , invoiceItemType = InvoiceItemTypeItem
120 , invoiceItemPeriod = Period{periodBeginning = "2000-01-01", periodEnd = "2000-01-01"}
121 , invoiceItemRate = 0
122 , invoiceItemQuantity = 0
123 }
124
125 data InvoiceItemType
126 = InvoiceItemTypeItem
127 | InvoiceItemTypeService
128 deriving (Eq, Ord, Show)
129
130 data Period = Period
131 { periodBeginning :: LocalTime
132 , periodEnd :: LocalTime
133 }
134 deriving (Eq, Ord, Show, Generic, NFData)