packages feed

bgmax (empty) → 0.1.0.0

raw patch · 5 files changed

+436/−0 lines, 5 filesdep +attoparsecdep +basedep +bytestringsetup-changed

Dependencies added: attoparsec, base, bytestring, time

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, Petter Bergman++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Petter Bergman nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ bgmax.cabal view
@@ -0,0 +1,34 @@+-- Initial bgmax.cabal generated by cabal init.  For further documentation,+--  see http://haskell.org/cabal/users-guide/++name:                bgmax+version:             0.1.0.0+synopsis:            Parse BgMax-files+homepage:            http://petterbergman.se/bgmax.html+license:             BSD3+license-file:        LICENSE+author:              Petter Bergman+maintainer:          jon.petter.bergman@gmail.com+-- copyright:           +category:            Finance+build-type:          Simple+-- extra-source-files:  +cabal-version:       >=1.10+description:         +  A low-level parser for +  <http://www.bgc.se/upload/Gemensamt/Trycksaker/Manualer/BG6040.pdf BgMax>+  -files from <http://www.bgc.se Bankgirocentralen> (BGC).+  It is able to parse all of the +  <http://www.bgc.se/templates/Iframe____3125.aspx example files> from BGC.++library+  exposed-modules:     Finance.BgMax.TK +                       Finance.BgMax.Parser+  -- other-modules:       +  other-extensions:    OverloadedStrings+  build-depends:       base >=4.7 && <4.8,+                       time >=1.4.2,+                       bytestring >=0.10.4.0,+                       attoparsec >=0.12.1.2+  hs-source-dirs:      src+  default-language:    Haskell98
+ src/Finance/BgMax/Parser.hs view
@@ -0,0 +1,185 @@+{-# LANGUAGE OverloadedStrings #-}+{- |+Module      :  $Header$+Description :  Parser for the BgMax file format+Copyright   :  (c) Petter Bergman+License     :  BSD3++Maintainer  :  jon.petter.bergman@gmail.com+Stability   :  experimental+Portability :  non-portable (OverloadedStrings)++This module contains a Parser for the +<http://www.bgc.se/upload/Gemensamt/Trycksaker/Manualer/BG6040.pdf BgMax>+format.++The parser tries to be forgiving with input it doesn't understand.+-}+module Finance.BgMax.Parser(parseBgMax) where+import Finance.BgMax.TK+import Data.ByteString.Char8(ByteString,dropWhile,reverse,readInt,readInteger,null,replicate)+import Data.Time(LocalTime(..),Day,TimeOfDay(..),fromGregorian)+import Data.Char(isSpace)+import Data.Attoparsec.ByteString.Char8(Parser,take,endOfLine,sepBy,string,skipWhile,notInClass)+import Prelude hiding (take,dropWhile,reverse,null,replicate)+import Control.Applicative((<|>),(*>),(<*>),(<$>),(<*))+import Data.Fixed(Pico)++class N a where+  readN :: ByteString -> Maybe (a,ByteString)++instance N Int where+  readN = readInt++instance N Integer where+  readN = readInteger+  +readFullN :: N a => ByteString -> Parser a+readFullN bs = +  case readN bs of+    Nothing -> fail $ "could not read as Int: " ++ show bs+    Just (x,bs') | null bs' -> return x+                 | otherwise -> fail $ "could not read all characters as Int: " ++ show bs'++n' :: N a => ByteString -> Parser a+n' = readFullN++n :: N a => Int -> Parser a+n c = take c >>= n'++nhb' :: N a => ByteString -> Parser a+nhb' = readFullN . dropWhile isSpace++nhb :: N a => Int -> Parser a+nhb c = take c >>= nhb'++orBlank :: (Int -> Parser a) -> Int -> Parser (Maybe a)+orBlank p c = (fmap Just $ p c) <|> (string (replicate c ' ') *> (return Nothing))++avb' :: ByteString -> ByteString+avb' = reverse . dropWhile isSpace . reverse++avb :: Int -> Parser ByteString+avb = fmap avb' . take++ab' :: ByteString -> ByteString+ab' = dropWhile isSpace++ab :: Int -> Parser ByteString+ab = fmap ab' . take++pOrT :: Parser TestMark+pOrT =+  "T" *> return T <|>+  "P" *> return P++parseCurrency :: Parser Currency+parseCurrency =+  "EUR" *> return EUR <|>+  "SEK" *> return SEK++makeReference :: Int -> ByteString -> Parser Reference+makeReference 0 _ = return Ref0+makeReference 1 _ = return Ref1+makeReference 2 bs = fmap Ref2 $ nhb' bs+makeReference 3 bs = return $ Ref3 $ ab' bs+makeReference 4 bs = return $ Ref4 $ avb' bs+makeReference 5 bs = return $ Ref5 $ ab' bs+makeReference i bs = return $ Ref i bs++parseDepositType :: Parser DepositType+parseDepositType = "K" *> return K <|>+                   "D" *> return D <|>+                   "S" *> return S++parseDay :: Parser Day+parseDay = fromGregorian <$> n 4 <*> n 2 <*> n 2++parseMicroseconds :: Parser Pico+parseMicroseconds =+  do+    second <- n 2+    microsecond <- n 6+    return $ (fromInteger second) + ((fromInteger microsecond) / 1000000)++parseTimeOfDay :: Parser TimeOfDay+parseTimeOfDay = TimeOfDay <$> n 2 <*> n 2 <*> parseMicroseconds++localTime :: Parser LocalTime+localTime = LocalTime <$> parseDay <*> parseTimeOfDay++parseTransaction :: Parser Transaction+parseTransaction = +  do+    sBG <- n 10+    ref' <- take 25+    amm <- n 18+    refCode <- n 1+    chan <- n 1+    bglNo <- n 12+    imag <- n 1+    ref <- makeReference refCode ref'+    return $ Transaction sBG ref amm chan bglNo imag++parsePost :: Parser a -> Parser b -> Parser b+parsePost code make = code *> make <* skipWhile (== ' ')++tk01 :: Parser Post+tk01 = fmap TK01 $ parsePost "01" $ TK01_t <$> avb 20 <*> n 2 <*> localTime <*> pOrT++tk05 :: Parser Post+tk05 = fmap TK05 $ parsePost "05" $ TK05_t <$> n 10 <*> orBlank n 10 <*> parseCurrency++tk20 :: Parser Post+tk20 = fmap TK20 $ parsePost "20" $ TK20_t <$> parseTransaction++tk21 :: Parser Post+tk21 = fmap TK21 $ parsePost "21" $ TK21_t <$> parseTransaction <*> n 1++tk22 :: Parser Post+tk22 = fmap TK22 $ parsePost "22" $ TK22_t <$> parseTransaction++tk23 :: Parser Post+tk23 = fmap TK23 $ parsePost "23" $ TK23_t <$> parseTransaction++tk25 :: Parser Post+tk25 = fmap TK25 $ parsePost "25" $ TK25_t <$> ab 50++tk26 :: Parser Post+tk26 = fmap TK26 $ parsePost "26" $ TK26_t <$> avb 35 <*> avb 35++tk27 :: Parser Post+tk27 = fmap TK27 $ parsePost "27" $ TK27_t <$> avb 35 <*> avb 9++tk28 :: Parser Post+tk28 = fmap TK28 $ parsePost "28" $ TK28_t <$> avb 35 <*> avb 35 <*> avb 2++tk29 :: Parser Post+tk29 = fmap TK29 $ parsePost "29" $ TK29_t <$> n 12++tk15 :: Parser Post+tk15 = fmap TK15 $ parsePost "15" $ TK15_t <$> n 35 <*> parseDay <*> n 5 <*> n 18 <*> parseCurrency <*> n 8 <*> orBlank (const parseDepositType) 1++tk70 :: Parser Post+tk70 = fmap TK70 $ parsePost "70" $ TK70_t <$> n 8 <*> n 8 <*> n 8 <*> n 8++tk :: Parser Post+tk = (TK <$> n 2) <* skipWhile (notInClass "\n\r")++-- | Parser for BgMax posts.+parseBgMax :: Parser [Post]+parseBgMax = sepBy go endOfLine +  where go = tk01 <|> +             tk05 <|> +             tk20 <|> +             tk21 <|> +             tk22 <|> +             tk23 <|> +             tk25 <|>+             tk26 <|>+             tk27 <|>+             tk28 <|>+             tk29 <|>+             tk15 <|> +             tk70 <|>+             tk
+ src/Finance/BgMax/TK.hs view
@@ -0,0 +1,185 @@+{- |+Module      :  $Header$+Description :  Datatypes for the BgMax file format+Copyright   :  (c) Petter Bergman+License     :  BSD3++Maintainer  :  jon.petter.bergman@gmail.com+Stability   :  experimental+Portability :  portable++This module contain data definitions for the different types of "Posts" or +"Transaction Codes" that may occur in a BgMax file, as well as auxiliary+data types. ++The datatypes should map in a straightforward way to the +documentation from <http://www.bgc.se/upload/Gemensamt/Trycksaker/Manualer/BG6040.pdf Bankgirocentralen>.+-}+module Finance.BgMax.TK where+import Data.Time(LocalTime(..),Day)+import Data.ByteString(ByteString)++-- | Testmark+data TestMark = +    T -- ^ Test file  +  | P -- ^ Production file +  deriving Show++-- | BankGirot currently only supports EUR and SEK+data Currency = EUR | SEK deriving Show++-- | Reference.+--   The references correspond to the reference codes defined in+--   <http://www.bgc.se/upload/Gemensamt/Trycksaker/Manualer/BG6040.pdf the BgMax documentation>.+data Reference = +  -- | No reference.+    Ref0+  -- | No reference. +  | Ref1 +  -- | Reference is correct OCR-no.+  | Ref2 Integer+  -- | One or more references.+  | Ref3 ByteString+  -- | One reference.+  | Ref4 ByteString+  -- | Incorrect reference.+  | Ref5 ByteString+  -- | Reserved for future use.+  | Ref Int ByteString +  deriving Show++-- | Deposit type.+--   Deposit type according to bank agreement.+data DepositType = K | D | S deriving Show++-- | Transaction type reused in TK 20,21,22,23.+data Transaction = +  Transaction {+    senderBG :: Integer,+    reference :: Reference,+    ammount :: Integer,+    -- | See the BGC documentation for the meaning of payment channel code.+    paymentChannel :: Int,+    bcgNo :: Integer,+    -- | See the BGC documentation for the meaning of the image mark.+    imageMark :: Int } +    deriving Show++-- | Start post.+data TK01_t =+  TK01_t {+    layoutName :: ByteString,+    layoutVersion :: Int,+    timeStamp :: LocalTime,+    testMark :: TestMark } +    deriving Show++-- | Opening post.+data TK05_t =+  TK05_t {+    recipientBG :: Integer,+    recipientPG :: Maybe Integer,+    currency :: Currency } +    deriving Show++-- | Payment post.+data TK20_t =+  TK20_t {+    payment :: Transaction } +    deriving Show++-- | Deduction post.+data TK21_t =+  TK21_t {+    deduction :: Transaction,+    -- | See the BGC documentation for the meaning of the deduction code.+    deductionCode :: Int } +    deriving Show++-- | Extra reference post.+data TK22_t =+  TK22_t {+    positiveReference :: Transaction } +    deriving Show++-- | Extra reference post (negative ammount).+data TK23_t =+  TK23_t {+    negativeReference :: Transaction } +    deriving Show++-- | Information post.+data TK25_t =+  TK25_t {+    information :: ByteString } +    deriving Show++-- | Name post.+data TK26_t =+  TK26_t {+    name :: ByteString,+    extraName :: ByteString } +    deriving Show++-- | Address 1 post.+data TK27_t =+  TK27_t {+    address :: ByteString,+    zipCode :: ByteString } +    deriving Show++-- | Address 2 post.+data TK28_t =+  TK28_t {+    city :: ByteString,+    country :: ByteString,+    countryCode :: ByteString } +    deriving Show++-- | Organisation-number post.+data TK29_t = +  TK29_t {+    orgNo :: Integer } +    deriving Show++-- | Deposit post.+data TK15_t =+  TK15_t {+    recipientAccount :: Integer,+    paymentDate :: Day,+    depositNo :: Int,+    depositAmmount :: Integer,+    depositCurrency :: Currency,+    paymentDeductionCount :: Int,+    depositType :: Maybe DepositType } +    deriving Show++-- | End post+data TK70_t =+  TK70_t {+    paymentsCount :: Int,+    deductionsCount :: Int,+    extraReferenceCount :: Int,+    depositCount :: Int } +    deriving Show++-- | Sum type for posts.+data Post =+    TK01 TK01_t+  | TK05 TK05_t+  | TK20 TK20_t+  | TK21 TK21_t+  | TK22 TK22_t+  | TK23 TK23_t+  | TK25 TK25_t+  | TK26 TK26_t+  | TK27 TK27_t+  | TK28 TK28_t+  | TK29 TK29_t+  | TK15 TK15_t+  | TK70 TK70_t+  -- | The BGC documentation states that implementations should ignore posts +  --   they don't understand, they will be instead be recorded using this +  --   constructor.+  | TK Int +  deriving Show