exchangealgebra-0.5.1.0: test/Golden/WriteRows.hs
{-# LANGUAGE OverloadedStrings #-}
module Golden.WriteRows
( writeRowsFixtureDir
, writeRowsFixtures
, renderRows
) where
import qualified Data.HashMap.Strict as HM
import qualified Data.List as L
import Data.Text (Text)
import qualified Data.Text as T
import Data.Time (Day, fromGregorian)
import ExchangeAlgebra
import ExchangeAlgebra.Bookkeeping
import qualified ExchangeAlgebra.Journal as EJ
import ExchangeAlgebra.Write
( accountLedgerRows
, accountLedgerRowsJournal
, bsRows
, compoundTrialBalanceRows
, journalRows
, plRows
, postClosingTrialBalanceRows
, worksheetRows
)
type MinBase = HatBase AccountTitles
type MinTransaction = Alg MoneyDecimal MinBase
type ADBase = HatBase (AccountTitles, Day)
type ADTransaction = Alg MoneyDecimal ADBase
writeRowsFixtureDir :: FilePath
writeRowsFixtureDir = "test/fixtures/write-rows-0510"
baselineCommit :: Text
baselineCommit = "250cbf15d9663f163f98f0ce3650f057de80170d"
fixture :: Text -> [[Text]] -> Text
fixture description rows =
"# write-rows-0510 " <> description
<> "; schema 1; commit " <> baselineCommit <> "\n"
<> renderRows rows
-- | Render rows as readable TSV, escaping cell content without using 'show'.
renderRows :: [[Text]] -> Text
renderRows = T.unlines . L.map (T.intercalate "\t" . L.map escapeCell)
where
escapeCell = T.replace "\n" "\\n"
. T.replace "\t" "\\t"
. T.replace "\\" "\\\\"
writeRowsFixtures :: [(FilePath, Text)]
writeRowsFixtures =
[ ( "ebex6-compound-trial-balance.tsv"
, fixture "compoundTrialBalanceRows ex6AllEntries"
(compoundTrialBalanceRows ex6AllEntries)
)
, ( "ebex7-compound-trial-balance.tsv"
, fixture "compoundTrialBalanceRows (foldr (.+) Zero (map snd ex7AllBalanced))"
(compoundTrialBalanceRows (foldr (.+) Zero (L.map snd ex7AllBalanced)))
)
, ( "ebex8-compound-trial-balance.tsv"
, fixture "compoundTrialBalanceRows (foldr (.+) Zero (map snd ex8SimpleBalanced))"
(compoundTrialBalanceRows (foldr (.+) Zero (L.map snd ex8SimpleBalanced)))
)
, ( "ebex8-journal.tsv"
, fixture "journalRows ex8CorrectionLedger ex8GetDay"
(journalRows ex8CorrectionLedger ex8GetDay)
)
, ( "ebex8-account-ledger.tsv"
, fixture "accountLedgerRows [Cash, AccountsReceivable, Sales] ex8CorrectionLedger ex8GetDay"
(accountLedgerRows [Cash, AccountsReceivable, Sales]
ex8CorrectionLedger ex8GetDay)
)
, ( "ebex8-account-ledger-journal.tsv"
, fixture "accountLedgerRowsJournal [Cash, AccountsReceivable, Sales] ex8Journal"
(accountLedgerRowsJournal [Cash, AccountsReceivable, Sales] ex8Journal)
)
, ( "ebex9-worksheet.tsv"
, fixture "worksheetRows ex9PreAdjustment ex9Adjustments"
(worksheetRows ex9PreAdjustment ex9Adjustments)
)
, ( "ebex9-post-closing-trial-balance.tsv"
, fixture "postClosingTrialBalanceRows ex9AfterClosing"
(postClosingTrialBalanceRows ex9AfterClosing)
)
, ( "ebex9-bs.tsv"
, fixture "bsRows ex9AfterClosing" (bsRows ex9AfterClosing)
)
, ( "ebex9-pl.tsv"
, fixture "plRows ex9PostAdjustment" (plRows ex9PostAdjustment)
)
]
-- ebex6 第9-15章: 現金預金, 商品売買, 債権債務の全28仕訳 (元の順序を維持).
ex6OverShortOccur, ex6OverShortFound, ex6OverShortClose :: MinTransaction
ex6OverShortOccur =
3000 .@ Not :< CashOverShort
.+ 3000 .@ Hat :< Cash
ex6OverShortFound =
2000 .@ Not :< CommunicationExpenses
.+ 2000 .@ Hat :< CashOverShort
ex6OverShortClose =
1000 .@ Not :< MiscellaneousLoss
.+ 1000 .@ Hat :< CashOverShort
ex6PettyCashAdvance, ex6PettyCashReplenish, ex6Overdraft :: MinTransaction
ex6PettyCashAdvance =
30000 .@ Not :< PettyCash
.+ 30000 .@ Hat :< CurrentDeposits
ex6PettyCashReplenish =
8000 .@ Not :< BusinessTrip
.+ 5000 .@ Not :< CommunicationExpenses
.+ 13000 .@ Hat :< CurrentDeposits
ex6Overdraft =
70000 .@ Not :< Purchases
.+ 40000 .@ Hat :< CurrentDeposits
.+ 30000 .@ Not :< BankOverdraft
ex6Purchase, ex6PurchaseReturn, ex6Sale, ex6SalesReturn :: MinTransaction
ex6Purchase =
120000 .@ Not :< Purchases
.+ 120000 .@ Not :< AccountsPayable
ex6PurchaseReturn =
20000 .@ Hat :< AccountsPayable
.+ 20000 .@ Hat :< Purchases
ex6Sale =
200000 .@ Not :< AccountsReceivable
.+ 200000 .@ Not :< Sales
ex6SalesReturn =
30000 .@ Hat :< Sales
.+ 30000 .@ Hat :< AccountsReceivable
ex6AdvancePaid, ex6AdvanceReceived :: MinTransaction
ex6AdvancePaid =
15000 .@ Not :< AdvancesPaid
.+ 15000 .@ Hat :< Cash
ex6AdvanceReceived =
25000 .@ Not :< Cash
.+ 25000 .@ Not :< AdvancesReceived
ex6CreditSale, ex6CreditCollect :: MinTransaction
ex6CreditSale =
96000 .@ Not :< CreditCardReceivable
.+ 4000 .@ Not :< PaymentFees
.+ 100000 .@ Not :< Sales
ex6CreditCollect =
96000 .@ Not :< CurrentDeposits
.+ 96000 .@ Hat :< CreditCardReceivable
ex6NotesReceivable, ex6NotesPayable, ex6ErReceivable :: MinTransaction
ex6NotesReceivable =
80000 .@ Not :< NotesReceivable
.+ 80000 .@ Not :< Sales
ex6NotesPayable =
60000 .@ Not :< Purchases
.+ 60000 .@ Not :< NotesPayable
ex6ErReceivable =
50000 .@ Not :< ElectronicallyRecordedReceivable
.+ 50000 .@ Hat :< AccountsReceivable
ex6ErObligation, ex6NotesLoanGiven, ex6NotesLoanTaken :: MinTransaction
ex6ErObligation =
40000 .@ Hat :< AccountsPayable
.+ 40000 .@ Not :< ElectronicallyRecordedObligations
ex6NotesLoanGiven =
150000 .@ Not :< NotesLoansReceivable
.+ 150000 .@ Hat :< Cash
ex6NotesLoanTaken =
200000 .@ Not :< CurrentDeposits
.+ 200000 .@ Not :< NotesLoansPayable
ex6PaymentOnBehalf, ex6DepositsReceived, ex6SuspensePayment :: MinTransaction
ex6PaymentOnBehalf =
7000 .@ Not :< PaymentsOnBehalf
.+ 7000 .@ Hat :< Cash
ex6DepositsReceived =
180000 .@ Not :< WageExpenditure
.+ 12000 .@ Not :< DepositsReceived
.+ 168000 .@ Hat :< Cash
ex6SuspensePayment =
40000 .@ Not :< SuspensePayments
.+ 40000 .@ Hat :< Cash
ex6SuspensePaymentSettle, ex6SuspenseReceipt :: MinTransaction
ex6SuspensePaymentSettle =
35000 .@ Not :< BusinessTrip
.+ 5000 .@ Not :< Cash
.+ 40000 .@ Hat :< SuspensePayments
ex6SuspenseReceipt =
60000 .@ Not :< CurrentDeposits
.+ 60000 .@ Not :< SuspenseReceipts
ex6SuspenseReceiptSettle, ex6OtherReceivable, ex6OtherPayable :: MinTransaction
ex6SuspenseReceiptSettle =
60000 .@ Hat :< SuspenseReceipts
.+ 60000 .@ Hat :< AccountsReceivable
ex6OtherReceivable =
100000 .@ Not :< OtherReceivables
.+ 100000 .@ Hat :< Fixtures
ex6OtherPayable =
90000 .@ Not :< Fixtures
.+ 90000 .@ Not :< OtherPayables
ex6AllEntries :: MinTransaction
ex6AllEntries =
ex6OverShortOccur .+ ex6OverShortFound .+ ex6OverShortClose
.+ ex6PettyCashAdvance .+ ex6PettyCashReplenish .+ ex6Overdraft
.+ ex6Purchase .+ ex6PurchaseReturn .+ ex6Sale .+ ex6SalesReturn
.+ ex6AdvancePaid .+ ex6AdvanceReceived
.+ ex6CreditSale .+ ex6CreditCollect
.+ ex6NotesReceivable .+ ex6NotesPayable
.+ ex6ErReceivable .+ ex6ErObligation
.+ ex6NotesLoanGiven .+ ex6NotesLoanTaken
.+ ex6PaymentOnBehalf .+ ex6DepositsReceived
.+ ex6SuspensePayment .+ ex6SuspensePaymentSettle
.+ ex6SuspenseReceipt .+ ex6SuspenseReceiptSettle
.+ ex6OtherReceivable .+ ex6OtherPayable
-- ebex7 第16-18章: 貸倒れ, 固定資産, 減価償却の仕訳.
ex7Mk :: MkBase MinBase
ex7Mk = (:<)
ex7WriteOffWithinAllowance, ex7WriteOffShortfall :: MinTransaction
ex7WriteOffWithinAllowance =
40000 .@ Hat :< AllowanceForDoubtfulAccounts
.+ 40000 .@ Hat :< AccountsReceivable
ex7WriteOffShortfall =
50000 .@ Hat :< AllowanceForDoubtfulAccounts
.+ 20000 .@ Not :< BadDebtLoss
.+ 70000 .@ Hat :< AccountsReceivable
ex7WriteOffCurrentPeriod, ex7Recovery :: MinTransaction
ex7WriteOffCurrentPeriod =
10000 .@ Not :< BadDebtLoss
.+ 10000 .@ Hat :< AccountsReceivable
ex7Recovery =
8000 .@ Not :< Cash
.+ 8000 .@ Not :< RecoveryOfBadDebts
ex7AllowanceReplenish, ex7AllowanceReset :: MinTransaction
ex7AllowanceReplenish = allowanceReplenishmentEntry ex7Mk 30000 18000
ex7AllowanceReset = allowanceResetEntries ex7Mk 30000 18000
ex7Acquire, ex7SellWithGain, ex7SellWithLoss :: MinTransaction
ex7Acquire =
520000 .@ Not :< Fixtures
.+ 520000 .@ Hat :< CurrentDeposits
ex7SellWithGain =
360000 .@ Hat :< AccumulatedDepreciation
.+ 300000 .@ Not :< Cash
.+ 600000 .@ Hat :< Fixtures
.+ 60000 .@ Not :< GainOnSalesOfFixedAssets
ex7SellWithLoss =
360000 .@ Hat :< AccumulatedDepreciation
.+ 200000 .@ Not :< Cash
.+ 40000 .@ Not :< LossOnSalesOfFixedAssets
.+ 600000 .@ Hat :< Fixtures
ex7AnnualDepreciation :: MoneyDecimal
ex7AnnualDepreciation = 60000
ex7Indirect, ex7Direct, ex7Monthly :: MinTransaction
ex7Indirect = depreciationIndirectEntry ex7Mk ex7AnnualDepreciation
ex7Direct = depreciationDirectEntry ex7Mk ex7AnnualDepreciation Building
ex7Monthly = depreciationIndirectEntry ex7Mk (72000 * 6 `divDec` 12)
where
divDec a b = a / fromIntegral b
ex7AllBalanced :: [(String, MinTransaction)]
ex7AllBalanced =
[ ("ex16_writeOffWithinAllowance", ex7WriteOffWithinAllowance)
, ("ex16_writeOffShortfall", ex7WriteOffShortfall)
, ("ex16_writeOffCurrentPeriod", ex7WriteOffCurrentPeriod)
, ("ex16_recovery", ex7Recovery)
, ("ex16_allowanceReplenish", ex7AllowanceReplenish)
, ("ex16_allowanceReset", ex7AllowanceReset)
, ("ex17_acquire", ex7Acquire)
, ("ex17_sellWithGain", ex7SellWithGain)
, ("ex17_sellWithLoss", ex7SellWithLoss)
, ("ex18_indirect", ex7Indirect)
, ("ex18_direct", ex7Direct)
, ("ex18_monthly", ex7Monthly)
]
-- ebex8 第19-23章: 資本, 訂正仕訳, 経過勘定, 税の仕訳.
ex8Mk :: MkBase MinBase
ex8Mk = (:<)
ex8GetDay :: ADBase -> Day
ex8GetDay (_ :< (_, day)) = day
ex8D :: Integer -> Int -> Int -> Day
ex8D = fromGregorian
ex8WrongEntry, ex8CancelEntry, ex8CorrectEntry :: ADTransaction
ex8WrongEntry =
45000 .@ Not :< (Cash, ex8D 2024 3 10)
.+ 45000 .@ Not :< (Sales, ex8D 2024 3 10)
ex8CancelEntry = reversingEntry ex8WrongEntry
ex8CorrectEntry =
45000 .@ Not :< (Cash, ex8D 2024 3 15)
.+ 45000 .@ Hat :< (AccountsReceivable, ex8D 2024 3 15)
ex8CorrectionLedger :: ADTransaction
ex8CorrectionLedger = ex8WrongEntry .+ ex8CancelEntry .+ ex8CorrectEntry
ex8IssueStock, ex8Dividend, ex8PayDividend :: MinTransaction
ex8IssueStock =
(200 * 5000) .@ Not :< CurrentDeposits
.+ (200 * 5000) .@ Not :< CapitalStock
ex8Dividend =
330000 .@ Hat :< RetainedEarnings
.+ 300000 .@ Not :< UnpaidDividends
.+ 30000 .@ Not :< LegalRetainedEarnings
ex8PayDividend =
300000 .@ Hat :< UnpaidDividends
.+ 300000 .@ Hat :< CurrentDeposits
ex8Prepaid, ex8Unearned, ex8AccruedRev, ex8AccruedExp :: MinTransaction
ex8Prepaid = prepaidExpenseEntry ex8Mk 12000 RentExpense
ex8Unearned = unearnedRevenueEntry ex8Mk 9000 RentalIncome
ex8AccruedRev = accruedRevenueEntry ex8Mk 6000 InterestEarned
ex8AccruedExp = accruedExpenseEntry ex8Mk 7500 InterestExpense
ex8Reversal, ex8ConsumptionTax, ex8CorpTaxInterim, ex8CorpTaxSettle :: MinTransaction
ex8Reversal = reversingEntry
(ex8Prepaid .+ ex8Unearned .+ ex8AccruedRev .+ ex8AccruedExp)
ex8ConsumptionTax = consumptionTaxSettlementEntry ex8Mk 20000 35000
ex8CorpTaxInterim = corporateTaxInterimEntry ex8Mk 40000
ex8CorpTaxSettle = corporateTaxSettlementEntries ex8Mk 90000 40000
ex8SimpleBalanced :: [(String, MinTransaction)]
ex8SimpleBalanced =
[ ("ex19_issueStock", ex8IssueStock)
, ("ex19_dividend", ex8Dividend)
, ("ex19_payDividend", ex8PayDividend)
, ("ex21_prepaid", ex8Prepaid)
, ("ex21_unearned", ex8Unearned)
, ("ex21_accruedRev", ex8AccruedRev)
, ("ex21_accruedExp", ex8AccruedExp)
, ("ex21_reversal", ex8Reversal)
, ("ex23_consumptionTax", ex8ConsumptionTax)
, ("ex23_corpTaxInterim", ex8CorpTaxInterim)
, ("ex23_corpTaxSettle", ex8CorpTaxSettle)
]
ex8Journal :: EJ.Journal String MoneyDecimal ADBase
ex8Journal = EJ.fromMap (HM.fromList
[ ("20-1 wrong entry", ex8WrongEntry)
, ("20-2 cancel entry", ex8CancelEntry)
, ("20-3 correct entry", ex8CorrectEntry)
])
-- ebex9 第24-25章: 決算整理から財務諸表までの総合仕訳.
ex9Mk :: MkBase MinBase
ex9Mk = (:<)
ex9Opening :: MinTransaction
ex9Opening =
500000 .@ Not :< Cash
.+ 300000 .@ Not :< CurrentDeposits
.+ 200000 .@ Not :< AccountsReceivable
.+ 80000 .@ Not :< MerchandiseInventory
.+ 600000 .@ Not :< Fixtures
.+ 120000 .@ Not :< AccumulatedDepreciation
.+ 4000 .@ Not :< AllowanceForDoubtfulAccounts
.+ 150000 .@ Not :< AccountsPayable
.+ 200000 .@ Not :< LoansPayable
.+ 1000000 .@ Not :< CapitalStock
.+ 206000 .@ Not :< RetainedEarnings
ex9T01, ex9T02, ex9T03, ex9T04, ex9T05 :: MinTransaction
ex9T01 = 400000 .@ Not :< Purchases .+ 400000 .@ Not :< AccountsPayable
ex9T02 = 900000 .@ Not :< AccountsReceivable .+ 900000 .@ Not :< Sales
ex9T03 = 500000 .@ Not :< Cash .+ 500000 .@ Hat :< AccountsReceivable
ex9T04 = 350000 .@ Hat :< AccountsPayable .+ 350000 .@ Hat :< CurrentDeposits
ex9T05 = 180000 .@ Not :< WageExpenditure .+ 180000 .@ Hat :< Cash
ex9T06, ex9T07, ex9T08, ex9T09, ex9T10 :: MinTransaction
ex9T06 = 120000 .@ Not :< RentExpense .+ 120000 .@ Hat :< Cash
ex9T07 = 40000 .@ Not :< Cash .+ 40000 .@ Not :< ReceiptFee
ex9T08 = 15000 .@ Not :< CommunicationExpenses .+ 15000 .@ Hat :< Cash
ex9T09 = 25000 .@ Not :< BusinessTrip .+ 25000 .@ Hat :< Cash
ex9T10 = 6000 .@ Not :< InterestExpense .+ 6000 .@ Hat :< Cash
ex9T11, ex9T12, ex9T13, ex9T14, ex9T15 :: MinTransaction
ex9T11 = 100000 .@ Not :< Fixtures .+ 100000 .@ Not :< OtherPayables
ex9T12 =
3000 .@ Hat :< AllowanceForDoubtfulAccounts
.+ 3000 .@ Hat :< AccountsReceivable
ex9T13 = 100000 .@ Not :< Cash .+ 100000 .@ Hat :< CurrentDeposits
ex9T14 = 8000 .@ Not :< SuppliesExpenses .+ 8000 .@ Hat :< Cash
ex9T15 = 12000 .@ Not :< UtilitiesExpense .+ 12000 .@ Hat :< Cash
ex9PeriodTransactions :: MinTransaction
ex9PeriodTransactions =
ex9T01 .+ ex9T02 .+ ex9T03 .+ ex9T04 .+ ex9T05 .+ ex9T06
.+ ex9T07 .+ ex9T08 .+ ex9T09 .+ ex9T10 .+ ex9T11 .+ ex9T12
.+ ex9T13 .+ ex9T14 .+ ex9T15
ex9PreAdjustment :: MinTransaction
ex9PreAdjustment = ex9Opening .+ ex9PeriodTransactions
ex9AdjCOGS, ex9AdjDepreciation, ex9AdjAllowance, ex9AdjPrepaid :: MinTransaction
ex9AdjCOGS = cogsAdjustmentEntries ex9Mk 80000 110000
ex9AdjDepreciation = depreciationIndirectEntry ex9Mk 70000
ex9AdjAllowance = allowanceReplenishmentEntry ex9Mk 7000 1000
ex9AdjPrepaid = prepaidExpenseEntry ex9Mk 30000 RentExpense
ex9Adjustments :: MinTransaction
ex9Adjustments = ex9AdjCOGS .+ ex9AdjDepreciation .+ ex9AdjAllowance .+ ex9AdjPrepaid
ex9PostAdjustment :: MinTransaction
ex9PostAdjustment = ex9PreAdjustment .+ ex9Adjustments
ex9NominalLedger :: MinTransaction
ex9NominalLedger = ExchangeAlgebra.filter isNominal ex9PostAdjustment
where
isNominal x = let division = (whatDiv . _hatBase) x
in division == Cost || division == Revenue
ex9IncomeSummary :: MinTransaction
ex9IncomeSummary = incomeSummaryAccount ex9NominalLedger
ex9AfterClosing :: MinTransaction
ex9AfterClosing = realLedger .+ netIncomeTransfer
( projByAccountTitle NetIncome ex9IncomeSummary
.+ projByAccountTitle NetLoss ex9IncomeSummary
)
where
realLedger = ExchangeAlgebra.filter isReal ex9PostAdjustment
isReal x = let division = (whatDiv . _hatBase) x
in division == Assets || division == Liability || division == Equity