2019-04-16 12:02:41 +00:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2019-07-28 09:55:22 +00:00
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
|
|
{-# LANGUAGE Arrows #-}
|
2019-10-19 19:39:41 +00:00
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
2019-07-18 15:09:26 +00:00
|
|
|
module Model.Product where
|
2019-04-15 20:23:25 +00:00
|
|
|
|
2019-07-21 13:02:59 +00:00
|
|
|
import Data.Text as T hiding (head, foldl)
|
2019-12-14 23:03:49 +00:00
|
|
|
import Data.Time (getCurrentTime)
|
2019-07-28 09:55:22 +00:00
|
|
|
import Data.Time.Clock (UTCTime)
|
|
|
|
import Data.Profunctor.Product (p9)
|
2019-04-15 20:23:25 +00:00
|
|
|
|
2019-07-18 12:57:35 +00:00
|
|
|
import Control.Monad.IO.Class (liftIO)
|
|
|
|
|
2019-10-21 18:40:30 +00:00
|
|
|
import Control.Arrow
|
2019-07-18 12:57:35 +00:00
|
|
|
|
2019-04-16 12:02:41 +00:00
|
|
|
import qualified Database.PostgreSQL.Simple as PGS
|
|
|
|
|
2019-10-21 18:40:30 +00:00
|
|
|
import qualified Data.Profunctor as P
|
|
|
|
|
|
|
|
import Opaleye as O
|
2019-07-18 12:57:35 +00:00
|
|
|
import Opaleye.Constant as C
|
|
|
|
|
|
|
|
-- internal imports
|
|
|
|
|
|
|
|
import Types
|
2019-07-28 09:55:22 +00:00
|
|
|
import Model.Amount
|
2019-04-15 20:23:25 +00:00
|
|
|
|
2019-07-18 15:09:26 +00:00
|
|
|
initProduct :: PGS.Query
|
2019-07-21 14:05:05 +00:00
|
|
|
initProduct = mconcat
|
2019-08-10 09:40:01 +00:00
|
|
|
[ "CREATE TABLE IF NOT EXISTS \"product\" ("
|
|
|
|
, "product_id SERIAL PRIMARY KEY,"
|
|
|
|
, "product_ident TEXT NOT NULL,"
|
|
|
|
, "product_ml INTEGER NOT NULL,"
|
|
|
|
, "product_avatar INTEGER,"
|
|
|
|
, "product_supplier INTEGER,"
|
|
|
|
, "product_max_amount INTEGER NOT NULL,"
|
|
|
|
, "product_amount_per_crate INTEGER NOT NULL,"
|
|
|
|
, "product_price_per_crate INTEGER,"
|
|
|
|
, "product_art_nr TEXT"
|
2019-07-21 13:02:59 +00:00
|
|
|
, ")"
|
|
|
|
]
|
2019-04-16 12:02:41 +00:00
|
|
|
|
2019-07-18 15:09:26 +00:00
|
|
|
productTable :: Table
|
2019-04-16 12:02:41 +00:00
|
|
|
( Maybe (Field SqlInt4)
|
|
|
|
, Field SqlText
|
|
|
|
, Field SqlInt4
|
2019-04-15 20:23:25 +00:00
|
|
|
, FieldNullable SqlInt4
|
|
|
|
, FieldNullable SqlInt4
|
2019-04-16 12:02:41 +00:00
|
|
|
, Field SqlInt4
|
|
|
|
, Field SqlInt4
|
|
|
|
, FieldNullable SqlInt4
|
2019-04-15 20:23:25 +00:00
|
|
|
, FieldNullable SqlText
|
|
|
|
)
|
2019-04-16 12:02:41 +00:00
|
|
|
( Field SqlInt4
|
|
|
|
, Field SqlText
|
|
|
|
, Field SqlInt4
|
|
|
|
, FieldNullable SqlInt4
|
2019-04-15 20:23:25 +00:00
|
|
|
, FieldNullable SqlInt4
|
2019-04-16 12:02:41 +00:00
|
|
|
, Field SqlInt4
|
|
|
|
, Field SqlInt4
|
2019-04-15 20:23:25 +00:00
|
|
|
, FieldNullable SqlInt4
|
|
|
|
, FieldNullable SqlText
|
|
|
|
)
|
2019-07-18 15:09:26 +00:00
|
|
|
productTable = table "product" (
|
2019-07-28 09:55:22 +00:00
|
|
|
p9
|
2019-07-18 15:09:26 +00:00
|
|
|
( tableField "product_id"
|
|
|
|
, tableField "product_ident"
|
|
|
|
, tableField "product_ml"
|
|
|
|
, tableField "product_avatar"
|
|
|
|
, tableField "product_supplier"
|
|
|
|
, tableField "product_max_amount"
|
|
|
|
, tableField "product_amount_per_crate"
|
|
|
|
, tableField "product_price_per_crate"
|
|
|
|
, tableField "product_art_nr"
|
2019-04-15 20:23:25 +00:00
|
|
|
)
|
|
|
|
)
|
2019-07-18 12:57:35 +00:00
|
|
|
|
2019-07-28 09:55:22 +00:00
|
|
|
|
2019-07-18 15:09:26 +00:00
|
|
|
productSelect
|
2019-07-18 12:57:35 +00:00
|
|
|
:: PGS.Connection
|
2019-07-18 15:09:26 +00:00
|
|
|
-> MateHandler [Product]
|
|
|
|
productSelect conn = do
|
2019-08-06 18:15:54 +00:00
|
|
|
prods <- liftIO $ runSelect conn
|
2019-07-18 15:09:26 +00:00
|
|
|
( keepWhen (\_ -> C.constant True) <<< queryTable productTable
|
2019-07-18 12:57:35 +00:00
|
|
|
) :: MateHandler
|
|
|
|
[ ( Int
|
|
|
|
, T.Text
|
|
|
|
, Int
|
|
|
|
, Maybe Int
|
|
|
|
, Maybe Int
|
|
|
|
, Int
|
2019-07-28 09:55:22 +00:00
|
|
|
, Int
|
|
|
|
, Maybe Int
|
|
|
|
, Maybe T.Text
|
|
|
|
)
|
|
|
|
]
|
|
|
|
mapM
|
2019-08-10 09:37:24 +00:00
|
|
|
(\(i1, i2, i3, i4, i5, i6, i7, i8, i9) -> return $
|
|
|
|
Product i1 i2 i3 i4 i5 i6 i7 i8 i9
|
2019-07-28 09:55:22 +00:00
|
|
|
)
|
2019-08-06 18:15:54 +00:00
|
|
|
prods
|
2019-07-28 09:55:22 +00:00
|
|
|
|
|
|
|
|
2019-12-14 23:03:49 +00:00
|
|
|
productSelectSingle
|
|
|
|
:: Int
|
|
|
|
-> PGS.Connection
|
|
|
|
-> MateHandler [Product]
|
|
|
|
productSelectSingle pid conn = do
|
|
|
|
prods <- liftIO $ runSelect conn
|
|
|
|
( limit 1
|
|
|
|
(keepWhen (
|
|
|
|
\(id_, _, _, _, _, _, _, _, _) -> id_ .== C.constant pid
|
|
|
|
) <<< queryTable productTable)
|
|
|
|
) :: MateHandler
|
|
|
|
[ ( Int
|
|
|
|
, T.Text
|
|
|
|
, Int
|
|
|
|
, Maybe Int
|
|
|
|
, Maybe Int
|
|
|
|
, Int
|
|
|
|
, Int
|
|
|
|
, Maybe Int
|
|
|
|
, Maybe T.Text
|
|
|
|
)
|
|
|
|
]
|
|
|
|
mapM
|
|
|
|
(\(i1, i2, i3, i4, i5, i6, i7, i8, i9) -> return $
|
|
|
|
Product i1 i2 i3 i4 i5 i6 i7 i8 i9
|
|
|
|
)
|
|
|
|
prods
|
|
|
|
|
|
|
|
|
2019-07-28 09:55:22 +00:00
|
|
|
productOverviewSelect
|
2019-09-09 11:17:43 +00:00
|
|
|
:: ProductRefine
|
|
|
|
-> PGS.Connection
|
2019-07-28 09:55:22 +00:00
|
|
|
-> MateHandler [ProductOverview]
|
2019-09-11 02:03:25 +00:00
|
|
|
productOverviewSelect refine conn = do
|
2019-10-21 18:40:30 +00:00
|
|
|
prods <- liftIO $ runSelect conn (produceProductOverviews refine)
|
2019-07-18 12:57:35 +00:00
|
|
|
mapM
|
2019-10-14 21:34:45 +00:00
|
|
|
(generateProductOverview conn)
|
2019-08-06 18:15:54 +00:00
|
|
|
prods
|
|
|
|
|
2019-10-21 18:40:30 +00:00
|
|
|
produceProductOverviews
|
|
|
|
:: ProductRefine
|
|
|
|
-> Select
|
|
|
|
( Column PGInt4
|
|
|
|
, Column PGText
|
|
|
|
, Column PGInt4
|
|
|
|
, Column (Nullable PGInt4)
|
|
|
|
, Column (Nullable PGInt4)
|
|
|
|
, Column PGInt4
|
|
|
|
, Column PGInt4
|
|
|
|
, Column (Nullable PGInt4)
|
|
|
|
, Column (Nullable PGText)
|
|
|
|
, Column PGInt4
|
|
|
|
, Column PGInt4
|
|
|
|
)
|
|
|
|
produceProductOverviews refine =
|
2019-12-12 02:15:56 +00:00
|
|
|
proc () -> do
|
|
|
|
(p, i2, i6, i7, i8, i9, i11, i12, i13, a3, a4)
|
|
|
|
<- orderBy (asc (\(_, a2, _, _, _, _, _, _, _, _, _) -> a2)) (leftJoinF
|
|
|
|
(\(pid, pi2, pi6, pi7, pi8, pi9, pi11, pi12, pi13)
|
|
|
|
(_, _, ai3, ai4, _) ->
|
|
|
|
(pid, pi2, pi6, pi7, pi8, pi9, pi11, pi12, pi13, ai3, ai4)
|
|
|
|
)
|
|
|
|
(const
|
|
|
|
( C.constant (0 :: Int) :: Column PGInt4
|
|
|
|
, C.constant ("ERROR PRODUCT" :: T.Text) :: Column PGText
|
|
|
|
, C.constant (0 :: Int) :: Column PGInt4
|
|
|
|
, C.constant (Just (0 :: Int)) :: Column (Nullable PGInt4)
|
|
|
|
, C.constant (Just (0 :: Int)) :: Column (Nullable PGInt4)
|
|
|
|
, C.constant (0 :: Int) :: Column PGInt4
|
|
|
|
, C.constant (0 :: Int) :: Column PGInt4
|
|
|
|
, C.constant (Just (0 :: Int)) :: Column (Nullable PGInt4)
|
|
|
|
, C.constant (Just ("" :: T.Text)) :: Column (Nullable PGText)
|
|
|
|
, C.constant (0 :: Int) :: Column PGInt4
|
|
|
|
, C.constant (0 :: Int) :: Column PGInt4
|
|
|
|
)
|
|
|
|
)
|
|
|
|
(\(pid, _, _, _, _, _, _, _, _)
|
|
|
|
(aid, _, _, _, _) ->
|
|
|
|
pid .== aid
|
|
|
|
)
|
|
|
|
(selectTable productTable)
|
|
|
|
(joinF
|
|
|
|
(\(_, _, a3, a4, a5) (b1, b2) ->
|
|
|
|
(b1, b2, a3, a4, a5)
|
2019-10-21 18:40:30 +00:00
|
|
|
)
|
2019-12-12 02:15:56 +00:00
|
|
|
(\(a1, a2, _, _, _) (b1, b2) ->
|
|
|
|
(a1 .== b1) .&& (a2 .== b2)
|
2019-10-21 18:40:30 +00:00
|
|
|
)
|
2019-12-12 02:15:56 +00:00
|
|
|
(selectTable amountTable)
|
|
|
|
(aggregate
|
|
|
|
((,)
|
|
|
|
<$> P.lmap fst O.groupBy
|
|
|
|
<*> P.lmap snd O.max
|
2019-10-21 18:40:30 +00:00
|
|
|
)
|
2019-12-12 02:15:56 +00:00
|
|
|
(arr (\(a, b, _, _, _) -> (a, b)) <<< selectTable amountTable))
|
|
|
|
)) -< ()
|
|
|
|
-- <<< arr (\_ -> (selectTable productTable, selectTable amountTable)) -< ()
|
|
|
|
restrict -< case refine of
|
|
|
|
AllProducts -> C.constant True
|
|
|
|
AvailableProducts -> a3 ./= (C.constant (0 :: Int) :: Column PGInt4)
|
|
|
|
DepletedProducts -> a3 .== (C.constant (0 :: Int) :: Column PGInt4)
|
|
|
|
returnA -< (p, i2, i6, i7, i8, i9, i11, i12, i13, a3, a4)
|
2019-10-21 18:40:30 +00:00
|
|
|
|
2019-10-14 21:34:45 +00:00
|
|
|
queryAmounts
|
|
|
|
:: PGS.Connection
|
|
|
|
-> Int
|
|
|
|
-> IO [(Int, UTCTime, Int, Int, Bool)]
|
|
|
|
queryAmounts conn pid = runSelect conn $ proc () -> do
|
|
|
|
stuff@(a1, _, _, _, _) <- orderBy (desc (\(_, ts, _, _, _) -> ts))
|
|
|
|
(queryTable amountTable) -< ()
|
|
|
|
restrict -< C.constant pid .== a1
|
|
|
|
returnA -< stuff
|
|
|
|
|
|
|
|
generateProductOverview
|
|
|
|
:: PGS.Connection
|
2019-10-21 18:40:30 +00:00
|
|
|
-> ( Int
|
|
|
|
, Text
|
|
|
|
, Int
|
|
|
|
, Maybe Int
|
|
|
|
, Maybe Int
|
|
|
|
, Int
|
|
|
|
, Int
|
|
|
|
, Maybe Int
|
|
|
|
, Maybe Text
|
|
|
|
, Int
|
|
|
|
, Int
|
|
|
|
)
|
2019-10-14 21:34:45 +00:00
|
|
|
-> MateHandler ProductOverview
|
2019-10-21 18:40:30 +00:00
|
|
|
generateProductOverview conn (i1, i2, i3, i4, i5, i6, i7, i8, i9, a3, a4) = do
|
2019-10-14 21:34:45 +00:00
|
|
|
amounts <- liftIO $ queryAmounts conn i1
|
|
|
|
let ii5 = snd $
|
|
|
|
foldl
|
|
|
|
(\(bef, van) (_, _, amo, _, ver) ->
|
|
|
|
if ver
|
|
|
|
then (amo, if amo < bef then van + (bef - amo) else van)
|
|
|
|
else (amo, van)
|
|
|
|
)
|
|
|
|
(0, 0)
|
|
|
|
(Prelude.reverse amounts)
|
|
|
|
ii10 = snd $ foldl (\(bef, tot) (_, _, amo, _, ver) ->
|
|
|
|
if ver
|
|
|
|
then (amo, tot)
|
2019-10-21 18:40:30 +00:00
|
|
|
else (amo, tot + Prelude.max 0 (bef - amo))
|
2019-10-14 21:34:45 +00:00
|
|
|
)
|
|
|
|
(0, 0)
|
|
|
|
(Prelude.reverse amounts)
|
|
|
|
return $ ProductOverview
|
2019-10-22 01:00:20 +00:00
|
|
|
i1 i2 a4 a3 ii5 i3 i4 i5 i6 ii10 i7 i8 i9
|
2019-08-06 18:15:54 +00:00
|
|
|
|
|
|
|
productOverviewSelectSingle
|
|
|
|
:: Int
|
|
|
|
-> PGS.Connection
|
|
|
|
-> MateHandler ProductOverview
|
|
|
|
productOverviewSelectSingle pid conn = do
|
2019-10-21 18:40:30 +00:00
|
|
|
prods <- liftIO $ runSelect conn (produceProductOverviews AllProducts)
|
2019-08-06 18:15:54 +00:00
|
|
|
head <$> mapM
|
2019-10-14 21:34:45 +00:00
|
|
|
(generateProductOverview conn)
|
2019-10-21 18:40:30 +00:00
|
|
|
(Prelude.filter (\(p, _, _, _, _, _, _, _, _, _, _) -> p == pid) prods)
|
2019-07-18 12:57:35 +00:00
|
|
|
|
2019-07-18 14:58:22 +00:00
|
|
|
|
2019-08-03 07:30:18 +00:00
|
|
|
productShortOverviewSelect
|
2019-10-04 07:01:44 +00:00
|
|
|
:: ProductRefine
|
|
|
|
-> PGS.Connection
|
2019-08-03 07:30:18 +00:00
|
|
|
-> MateHandler [ProductShortOverview]
|
2019-10-04 07:01:44 +00:00
|
|
|
productShortOverviewSelect refine conn = do
|
2019-10-21 18:40:30 +00:00
|
|
|
prods <- liftIO $ runSelect conn (produceProductOverviews refine)
|
2019-10-27 21:46:07 +00:00
|
|
|
:: MateHandler
|
|
|
|
[( Int
|
2019-10-21 18:40:30 +00:00
|
|
|
, Text
|
|
|
|
, Int
|
|
|
|
, Maybe Int
|
|
|
|
, Maybe Int
|
|
|
|
, Int
|
|
|
|
, Int
|
|
|
|
, Maybe Int
|
|
|
|
, Maybe Text
|
|
|
|
, Int
|
|
|
|
, Int
|
|
|
|
)]
|
2019-08-03 07:30:18 +00:00
|
|
|
mapM
|
2019-12-12 02:15:56 +00:00
|
|
|
(\(i1, i2, i3, i4, _, _, _, _, _, a3, a4) ->
|
2019-08-03 07:30:18 +00:00
|
|
|
return $ ProductShortOverview
|
2019-10-21 18:40:30 +00:00
|
|
|
i1 i2 a4 a3 i3 i4
|
2019-08-03 07:30:18 +00:00
|
|
|
)
|
2019-08-06 18:15:54 +00:00
|
|
|
prods
|
2019-08-03 07:30:18 +00:00
|
|
|
|
|
|
|
|
2019-07-18 15:09:26 +00:00
|
|
|
insertProduct
|
|
|
|
:: ProductSubmit
|
2019-07-28 09:55:22 +00:00
|
|
|
-> PGS.Connection
|
|
|
|
-> MateHandler Int
|
2019-09-07 00:48:16 +00:00
|
|
|
insertProduct (ProductSubmit ident _ ml ava sup maxi apc ppc artnr) conn =
|
2019-07-28 09:55:22 +00:00
|
|
|
fmap head $ liftIO $ runInsert_ conn $ Insert
|
|
|
|
{ iTable = productTable
|
|
|
|
, iRows =
|
|
|
|
[
|
|
|
|
( C.constant (Nothing :: Maybe Int)
|
|
|
|
, C.constant ident
|
|
|
|
, C.constant ml
|
|
|
|
, C.constant ava
|
|
|
|
, C.constant sup
|
2019-09-07 00:48:16 +00:00
|
|
|
, C.constant maxi
|
2019-07-28 09:55:22 +00:00
|
|
|
, C.constant apc
|
|
|
|
, C.constant ppc
|
|
|
|
, C.constant artnr
|
|
|
|
)
|
|
|
|
]
|
2019-08-09 18:56:04 +00:00
|
|
|
, iReturning = rReturning (\(id_, _, _, _, _, _, _, _, _) -> id_)
|
2019-07-28 09:55:22 +00:00
|
|
|
, iOnConflict = Nothing
|
|
|
|
}
|
2019-12-14 23:03:49 +00:00
|
|
|
|
|
|
|
manualProductAmountRefill
|
|
|
|
:: [AmountRefill]
|
|
|
|
-> PGS.Connection
|
|
|
|
-> MateHandler [Int]
|
|
|
|
manualProductAmountRefill aups conn =
|
|
|
|
mapM
|
|
|
|
(\(AmountRefill pid amountSingles amountCrates) -> do
|
|
|
|
oldamount <- getLatestAmountByProductId pid conn
|
|
|
|
oldprice <- getLatestPriceByProductId pid conn
|
2020-08-24 07:43:22 +00:00
|
|
|
perCrate <- productAmountPerCrate . head <$>
|
2019-12-14 23:03:49 +00:00
|
|
|
productSelectSingle pid conn
|
|
|
|
head <$> liftIO (do
|
|
|
|
now <- getCurrentTime
|
|
|
|
runInsert_ conn $ Insert
|
|
|
|
{ iTable = amountTable
|
|
|
|
, iRows =
|
|
|
|
[
|
|
|
|
( C.constant pid
|
|
|
|
, C.constant now
|
2019-12-19 01:40:54 +00:00
|
|
|
, C.constant (oldamount + (amountSingles + (perCrate * amountCrates)))
|
2019-12-14 23:03:49 +00:00
|
|
|
, C.constant oldprice
|
|
|
|
, C.constant False
|
|
|
|
)
|
|
|
|
]
|
|
|
|
, iReturning = rReturning (\(id_, _, _, _, _) -> id_)
|
|
|
|
, iOnConflict = Nothing
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
aups
|