/// <summary> /// Update Buy/Sell after editing /// </summary> public AjaxReturn DocumentSave(InvestmentDocument json) { Database.BeginTransaction(); JObject oldDoc = getCompleteDocument(json.idDocument); DocType t = checkDocType(json.DocumentTypeId, DocType.Buy, DocType.Sell); FullAccount acct = Database.Get <FullAccount>((int)json.DocumentAccountId); checkAcctType(acct.AccountTypeId, AcctType.Investment); int sign = SignFor(t); fixNameAddress(json, "O"); if (json.SecurityId == 0) { Utils.Check(!string.IsNullOrEmpty(json.SecurityName), "No Security Name supplied"); json.SecurityId = Database.ForeignKey("Security", "SecurityName", json.SecurityName); } if (string.IsNullOrEmpty(json.DocumentMemo)) { json.DocumentMemo = json.SecurityName; } if (json.idDocument == null) { StockPrice p = Database.QueryOne <StockPrice>("SELECT * FROM " + LatestPrice(Database, json.DocumentDate) + " WHERE SecurityId = " + json.SecurityId); if (p.Price != json.Price) { // Stock price is different from file price, and its a new buy/sell - update file price for security date p.SecurityId = (int)json.SecurityId; p.Date = json.DocumentDate; p.Price = json.Price; Database.Update(p); } } decimal cost = (decimal)Math.Round(json.Price * json.Quantity, 2); decimal amount = json.Fee + sign * cost; Database.Update(json); // First journal is posting to this account Journal journal = Database.Get(new Journal() { DocumentId = (int)json.idDocument, JournalNum = 1 }); journal.DocumentId = (int)json.idDocument; journal.AccountId = json.DocumentAccountId; journal.NameAddressId = json.DocumentNameAddressId; journal.Memo = json.DocumentMemo; journal.JournalNum = 1; journal.Amount = -amount; journal.Outstanding = -amount; Database.Update(journal); // Second journal is to subaccount for this security (account:security) journal = Database.Get(new Journal() { DocumentId = (int)json.idDocument, JournalNum = 2 }); journal.DocumentId = (int)json.idDocument; journal.AccountId = (int)Database.ForeignKey("Account", "AccountName", acct.AccountName + ":" + json.SecurityName, "AccountTypeId", (int)AcctType.Security); journal.NameAddressId = json.DocumentNameAddressId; journal.Memo = json.DocumentMemo; journal.JournalNum = 2; journal.Amount = journal.Outstanding = sign * cost; Database.Update(journal); // Corresponding line Line line = Database.Get <Line>((int)journal.idJournal); line.idLine = journal.idJournal; line.LineAmount = cost; Database.Update(line); // Now update the stock transaction StockTransaction st = Database.Get <StockTransaction>((int)journal.idJournal); st.idStockTransaction = journal.idJournal; st.ParentAccountId = json.DocumentAccountId; st.SecurityId = (int)json.SecurityId; st.Price = json.Price; st.Quantity = sign * json.Quantity; st.CostPer = Math.Round((double)amount / json.Quantity, 4); Database.Update(st); if (json.Fee != 0) { // Need another journal and line for the fee Utils.Check(json.FeeAccount > 0, "No Fee Account supplied"); journal = Database.Get(new Journal() { DocumentId = (int)json.idDocument, JournalNum = 3 }); journal.DocumentId = (int)json.idDocument; journal.AccountId = (int)json.FeeAccount; journal.NameAddressId = json.DocumentNameAddressId; journal.Memo = json.FeeMemo; journal.JournalNum = 3; journal.Amount = journal.Outstanding = json.Fee; Database.Update(journal); line = Database.Get <Line>((int)journal.idJournal); line.idLine = journal.idJournal; line.LineAmount = sign * json.Fee; Database.Update(line); } // Delete any left over lines from the old transaction Database.Execute("DELETE FROM Line WHERE idLine IN (SELECT idJournal FROM Journal WHERE DocumentId = " + json.idDocument + " AND JournalNum > " + journal.JournalNum + ")"); Database.Execute("DELETE FROM Journal WHERE Documentid = " + json.idDocument + " AND JournalNum > " + journal.JournalNum); // Audit JObject newDoc = getCompleteDocument(json.idDocument); Database.AuditUpdate("Document", json.idDocument, oldDoc, newDoc); Database.Commit(); return(new AjaxReturn() { message = "Document saved", id = json.idDocument }); }
/// <summary> /// Input a wierd Quicked double value (e.g. share price) /// </summary> double getDouble(string value) { if (value.Contains("/")) { string [] parts = value.Split(' '); if (parts.Length == 1) { parts = new string[] { "0", parts[0] } } ; Utils.Check(parts.Length == 2, "Invalid fraction value {0}", value); string[] fract = parts[1].Split('/'); Utils.Check(fract.Length == 2, "Invalid fraction value {0}", value); double d = double.Parse(parts[0]); double f = double.Parse(fract[0]) / double.Parse(fract[1]); d += d < 0 ? -f : f; return(d); } return(double.Parse(value)); } /// <summary> /// Get next line, split it into tag and value /// </summary> bool getLine() { do { _line = _reader.ReadLine(); Line++; } while (_line == ""); _eof = _line == null; if (!_eof) { _tag = _line.Substring(0, 1); _value = _line.Length > 1 ? _line.Substring(1) : ""; Character += _line.Length + 2; } return(!_eof); } /// <summary> /// Import account info for a bank/card/security accounts /// </summary> void importAccounts() { status("Importing Account"); JObject o = new JObject(); while (getLine()) { switch (_tag) { case "!": return; case "^": // End of record if (!string.IsNullOrEmpty(o.AsString("AccountName"))) { _account = (int)_module.Database.ForeignKey("Account", o); } o = new JObject(); break; case "N": o["AccountName"] = _accountName = _value; break; case "D": o["AccountDescription"] = _value; break; case "S": // Security stock ticker break; case "T": switch (_value) { case "CCard": o["AccountTypeId"] = (int)AcctType.CreditCard; break; case "Bank": o["AccountTypeId"] = (int)AcctType.Bank; break; case "Stock": case "Invst": case "Port": case "Mutual": case "401(k)": o["AccountTypeId"] = (int)AcctType.Investment; break; case "Oth A": o["AccountTypeId"] = (int)AcctType.OtherAsset; break; case "Oth L": case "Tax": case "Bill": o["AccountTypeId"] = (int)AcctType.OtherLiability; break; default: throw new CheckException("Unexpected account type:{0}", _line); } break; } } } /// <summary> /// Import series of categories (accounts, in our system) /// </summary> void importCategories() { status("Importing Categories"); JObject o = new JObject(); while (getLine()) { switch (_tag) { case "!": return; case "^": // End of record if (!string.IsNullOrEmpty(o.AsString("AccountName"))) { _account = (int)_module.Database.ForeignKey("Account", o); } o = new JObject(); break; case "N": o["AccountName"] = _accountName = _value; break; case "D": o["AccountDescription"] = _value; break; case "E": o["AccountTypeId"] = (int)AcctType.Expense; break; case "I": o["AccountTypeId"] = (int)AcctType.Income; break; case "B": break; } } } int nextTicker; void importInvestments() { decimal value; status("Importing Investments"); _accountsProcessed.Add(_account); startInvestment(); while (getLine()) { switch (_tag) { case "!": return; case "^": // End of record addInvestment(); startInvestment(); break; case "D": _transaction.DocumentDate = getDate(_value); break; case "M": // Memo if (_transaction.DocumentMemo == null) { _transaction.DocumentMemo = _value; } else if (_transaction.DocumentIdentifier == null) { _transaction.DocumentIdentifier = _value; } break; case "N": _transaction.DocumentIdentifier = _value; break; case "P": // Payee _transaction.Name = _value; break; case "T": // Amount value = decimal.Parse(_value); _transaction.DocumentTypeId = (int)(value < 0 ? DocType.Buy : DocType.Sell); _transaction.Amount = value; break; case "Y": // Security name if (!string.IsNullOrEmpty(_value)) { _transaction.SecurityName = _value; _transaction.Stock.SecurityId = (int)_module.Database.ForeignKey("Security", "SecurityName", _value, "Ticker", "T" + nextTicker++.ToString("00")); } break; case "Q": // Quantity (of shares) _transaction.Stock.Quantity = getDouble(_value); break; case "I": // Price _transaction.Stock.Price = getDouble(_value); break; case "O": // Commission cost value = decimal.Parse(_value); if (value != 0) { Journal j = new Journal(); _transaction.Journals.Add(j); j.AccountId = (int)_module.Database.ForeignKey("Account", "AccountName", _accountName + " fees", "AccountTypeId", (int)AcctType.OtherExpense); j.Memo = "Fees"; j.Amount = j.Outstanding = decimal.Parse(_value); } break; case "L": // Category/account account(); _detail.Amount = _detail.Outstanding = -_transaction.Amount; break; case "U": // ?? Same value as T case "$": // Split amount case "C": // Cleared case "E": // Split memo case "S": // Split category/account break; } } } /// <summary> /// Stock prices /// </summary> void importPrices() { status("Importing Prices"); while (getLine()) { switch (_tag) { case "!": return; case "^": // End of record getLine(); // Get next line for caller to process return; case "\"": string[] fields = _line.Split(','); string d = Utils.RemoveQuotes(fields[2]); StockPrice p = new StockPrice(); try { p.SecurityId = (int)_module.Database.ForeignKey("Security", "Ticker", Utils.RemoveQuotes(fields[0])); } catch (Exception ex) { // Security doesn't exist - ignore price break; } p.Price = getDouble(fields[1]); p.Date = getDate(d); _module.Database.Update(p);; break; } } } void importSecurity() { status("Importing Security"); JObject o = new JObject(); o["PriceDate"] = new DateTime(1900, 1, 1); while (getLine()) { switch (_tag) { case "!": return; case "^": // End of record if (!string.IsNullOrWhiteSpace(o.AsString("SecurityName")) && !string.IsNullOrWhiteSpace(o.AsString("Ticker"))) { _module.Database.ForeignKey("Security", o); } getLine(); // Get next line for caller to process return; case "N": o["SecurityName"] = _value; break; case "S": // Security stock ticker o["Ticker"] = _value; break; case "T": // Type? (Stock) break; } } } void importTransactions(DocType debit, DocType credit) { decimal value; string lAccount = null; status("Importing Transactions"); // For de-duplicating transfers _accountsProcessed.Add(_account); startTransaction(); while (getLine()) { switch (_tag) { case "!": return; case "^": addTransaction(); startTransaction(); lAccount = null; break; case "C": _transaction.Cleared = _value; break; case "D": _transaction.DocumentDate = getDate(_value); break; case "M": // Memo if (_transaction.DocumentMemo == null) { _transaction.DocumentMemo = _value; } else if (_transaction.DocumentIdentifier == null) { _transaction.DocumentIdentifier = _value; } break; case "N": _transaction.DocumentIdentifier = _value; break; case "E": // Split memo if (_detail.Memo != null) { _transaction.Journals.Add(_detail = new Journal()); } _detail.Memo = _value; break; case "L": // Category/account lAccount = _value; account(); // Generate an initial journal line (in case there are no S split lines) _detail.Amount = _detail.Outstanding = -_transaction.Amount; break; case "S": // Split category/account if (_value == lAccount && _transaction.Journals.Count == 1) { // Transaction has both L and S lines, and first S line is same as L // We must ignore the initial journal line we generated from the L line (in case there were no S lines) _detail.AccountId = 0; _detail.Amount = _detail.Outstanding = 0; } lAccount = null; account(); break; case "P": // Payee _transaction.Name = _value; break; case "T": // Amount value = decimal.Parse(_value); _transaction.DocumentTypeId = (int)(value < 0 ? debit : credit); _transaction.Amount = value; break; case "$": // Split amount value = -decimal.Parse(_value); if (value == 0) { // Value is zero - we need to remove this line and go back to previous one if (_transaction.Journals.Count > 1) { _detail = _transaction.Journals[_transaction.Journals.Count - 2]; _transaction.Journals.RemoveAt(_transaction.Journals.Count - 1); } else { // No previous line - re-initialise this line _detail = new Journal(); _transaction.Journals[0] = _detail; } break; } if (_detail.Amount != 0) { _transaction.Journals.Add(_detail = new Journal()); } _detail.Amount = value; _detail.Outstanding = value; break; case "U": // ?? Same value as T break; case "Y": // Security name case "Q": // Quantity (of shares) case "I": // Price case "O": // Commission cost break; } } } /// <summary> /// Have come across an account. /// If necessary add a new journal, and set AccountId /// </summary> void account() { if (string.IsNullOrEmpty(_value)) { return; } // Transfers are shown as "[accountname]" string a = Regex.Replace(_value, @"^\[(.*)\]$", "$1"); if (_detail.AccountId != 0) { _transaction.Journals.Add(_detail = new Journal()); } _detail.AccountId = _transactionsOnly ? (int)_module.Database.LookupKey("Account", "AccountName", a, "AccountTypeId", (int)AcctType.Expense) : (int)_module.Database.ForeignKey("Account", "AccountName", a, "AccountTypeId", (int)AcctType.Expense); if (a != _value) { _transaction.DocumentTypeId = (int)DocType.Transfer; } } /// <summary> /// Add an investment transaction to _transactions /// </summary> void addInvestment() { _transaction.NameAddressId = string.IsNullOrWhiteSpace(_transaction.Name) ? 1 : (int)_module.Database.ForeignKey("NameAddress", "Name", _transaction.Name, "Type", "O"); switch (_transaction.DocumentIdentifier) { case "Buy": addBuy(); return; case "BuyX": // Transfer money in from another account, and use it to buy addTransfer(-1); addBuy(); return; case "Sell": addSell(); return; case "SellX": // Sell and transfer money out to another account addSell(); addTransfer(1); return; case "ReinvDiv": // Receive a dividend and use it to buy addIncome("Dividends"); addBuy(); return; case "ReinvInt": // Receive interest and use it to buy addIncome("Interest"); addBuy(); return; case "Div": addIncome("Dividends"); return; case "DivX": // Receive a dividend and transfer it to another account addIncome("Dividends"); addTransfer(1); return; case "CGLong": addIncome("Long Term Capital Gains"); return; case "CGLongX": // Receive a gain and transfer it to another account addIncome("Long Term Capital Gains"); addTransfer(1); return; case "ReinvLg": // Receive gain and use it to buy addIncome("Long Term Capital Gains"); addBuy(); return; case "ReinvMd": // Receive gain and use it to buy addIncome("Mid Term Capital Gains"); addBuy(); return; case "ReinvSh": // Receive gain and use it to buy addIncome("Short Term Capital Gains"); addBuy(); return; case "CGMid": addIncome("Mid Term Capital Gains"); return; case "CGMidX": // Receive a gain and transfer it to another account addIncome("Mid Term Capital Gains"); addTransfer(1); return; case "CGShort": addIncome("Short Term Capital Gains"); return; case "CGShortX": // Receive a gain and transfer it to another account addIncome("Short Term Capital Gains"); addTransfer(1); return; case "IntInc": addIncome("Interest"); return; case "IntIncX": // Receive a dividend and transfer it to another account addIncome("Interest"); addTransfer(1); return; } if (_transaction.Journals[0].AccountId == 0) { addIncome(_transaction.DocumentIdentifier); return; } // Utils.Check(_transaction.Stock.SecurityId == 0, "Unexpected stock transaction {0}", _transaction.DocumentIdentifier); if (_accountsProcessed.Contains(_transaction.Journals[0].AccountId)) { setClearedStatus(_transaction); return; } _transaction.Stock = null; Account acct = _module.Database.Get <Account>(_transaction.Journals[0].AccountId); _transaction.DocumentTypeId = (int)(acct.AccountTypeId == (int)AcctType.Bank || acct.AccountTypeId == (int)AcctType.CreditCard || acct.AccountTypeId == (int)AcctType.Investment || acct.AccountTypeId == (int)AcctType.OtherAsset || acct.AccountTypeId == (int)AcctType.OtherLiability ? DocType.Transfer : _transaction.Amount < 0 ? DocType.Withdrawal : DocType.Deposit); _transactions.Add(_transaction); } void addBuy() { Utils.Check(_transaction.Stock.SecurityId != 0, "Stock transaction {0} without security", _transaction.DocumentIdentifier); Transaction t = _transaction.Clone <Transaction>(); t.DocumentTypeId = (int)DocType.Buy; t.DocumentMemo = _transaction.DocumentMemo ?? _transaction.SecurityName; decimal net = t.Amount; if (t.Journals.Count > 1) { net -= t.Journals[1].Amount; } t.Amount = -t.Amount; Journal d = t.Journals[0]; d.AccountId = (int)_module.Database.ForeignKey("Account", "AccountName", _accountName + ":" + t.SecurityName, "AccountTypeId", (int)AcctType.Security); d.Amount = d.Outstanding = net; d.Memo = t.Stock.Quantity + " at " + t.Stock.Price; _transactions.Add(t); } void addSell() { Utils.Check(_transaction.Stock.SecurityId != 0, "Stock transaction {0} without security", _transaction.DocumentIdentifier); Transaction t = _transaction.Clone <Transaction>(); t.DocumentTypeId = (int)DocType.Sell; t.DocumentMemo = _transaction.DocumentMemo ?? _transaction.SecurityName; decimal net = t.Amount; if (t.Journals.Count > 1) { net += t.Journals[1].Amount; } Journal d = t.Journals[0]; d.AccountId = (int)_module.Database.ForeignKey("Account", "AccountName", _accountName + ":" + t.SecurityName, "AccountTypeId", (int)AcctType.Security); d.Amount = d.Outstanding = -net; d.Memo = t.Stock.Quantity + " at " + t.Stock.Price; t.Stock.Quantity = -t.Stock.Quantity; _transactions.Add(t); } void addIncome(string accountName) { Transaction t = new Transaction(); t.AccountId = _account; t.Amount = _transaction.Amount; t.Cleared = _transaction.Cleared; t.DocumentDate = _transaction.DocumentDate; t.DocumentIdentifier = _transaction.DocumentIdentifier; t.DocumentMemo = _transaction.DocumentMemo ?? _transaction.SecurityName; t.DocumentTypeId = (int)DocType.Deposit; t.Line = _transaction.Line; t.NameAddressId = _transaction.NameAddressId; t.Journals.Add(new Journal() { AccountId = (int)_module.Database.ForeignKey("Account", "AccountName", accountName, "AccountTypeId", (int)AcctType.OtherIncome), Amount = -_transaction.Amount, Outstanding = -_transaction.Amount }); _transactions.Add(t); } void addTransfer(int sign) { Transaction t = new Transaction(); Account a = _module.Database.Get <Account>(_detail.AccountId); t.AccountId = _detail.AccountId; t.Amount = sign * _transaction.Amount; t.Cleared = _transaction.Cleared; t.DocumentDate = _transaction.DocumentDate; t.DocumentIdentifier = _transaction.DocumentIdentifier; t.DocumentMemo = _transaction.DocumentMemo ?? _transaction.SecurityName; t.DocumentTypeId = (int)(a.AccountTypeId == (int)AcctType.Bank || a.AccountTypeId == (int)AcctType.CreditCard || a.AccountTypeId == (int)AcctType.Investment || a.AccountTypeId == (int)AcctType.OtherAsset || a.AccountTypeId == (int)AcctType.OtherLiability ? DocType.Transfer : DocType.GeneralJournal); t.Line = _transaction.Line; t.NameAddressId = _transaction.NameAddressId; t.Journals.Add(new Journal() { AccountId = _account, Amount = -t.Amount, Outstanding = -t.Amount }); if (_accountsProcessed.Contains(_transaction.Journals[0].AccountId)) { setClearedStatus(t); return; } _transactions.Add(t); } /// <summary> /// Add current transaction to _transactions /// </summary> void addTransaction() { if (!_transactionsOnly) { _transaction.NameAddressId = string.IsNullOrWhiteSpace(_transaction.Name) ? 1 : (int)_module.Database.ForeignKey("NameAddress", "Name", _transaction.Name, "Type", "O"); if (_accountsProcessed.Contains(_transaction.Journals[0].AccountId)) { setClearedStatus(_transaction); return; } } _transactions.Add(_transaction); } /// <summary> /// Post all transactions in _transactions to the database /// </summary> void postTransactions() { _module.Batch.Record = 0; _module.Batch.Records = _transactions.Count; status("Updating database"); foreach (Transaction t in _transactions.OrderBy(t => t.DocumentDate)) { _module.Batch.Record++; decimal total = 0; Line = t.Line; Utils.Check(t.NameAddressId > 0, "No NameAddressId"); _module.Batch.Record++; _module.Database.Insert(t); int docid = (int)t.idDocument; int sign = t.DocumentTypeId == (int)DocType.Transfer || t.Amount < 0 ? 1 : -1; Journal j = new Journal(); j.DocumentId = docid; j.JournalNum = 1; j.NameAddressId = t.NameAddressId; j.AccountId = t.AccountId; j.Cleared = t.Cleared; j.Memo = t.DocumentMemo; j.Amount = j.Outstanding = t.Amount; total += j.Amount; _module.Database.Insert(j); for (int i = 0; i < t.Journals.Count; i++) { Journal d = t.Journals[i]; d.DocumentId = docid; d.JournalNum = i + 2; d.NameAddressId = t.NameAddressId; if (d.AccountId == 0) { d.AccountId = (int)_module.Database.ForeignKey("Account", "AccountName", "Uncategorised", "AccountTypeId", (int)AcctType.Expense); } total += d.Amount; _module.Database.Insert(d); Line l = new Line(); l.idLine = d.idJournal; l.LineAmount = sign * d.Amount; _module.Database.Insert(l); if (i == 0 && t.Stock != null && t.Stock.Quantity != 0) { t.Stock.idStockTransaction = d.idJournal; t.Stock.ParentAccountId = t.AccountId; t.Stock.CostPer = -(double)t.Amount / t.Stock.Quantity; _module.Database.Insert(t.Stock); } } if (total != 0 && AllowImbalancedTransactions) { Journal d = new Journal(); d.DocumentId = docid; d.JournalNum = t.Journals.Count + 2; d.NameAddressId = t.NameAddressId; d.AccountId = (int)_module.Database.ForeignKey("Account", "AccountName", "Imbalanced Transactions", "AccountTypeId", (int)AcctType.Expense); d.Amount = -total; total += d.Amount; _module.Database.Insert(d); Line l = new Line(); l.idLine = d.idJournal; l.LineAmount = sign * d.Amount; _module.Database.Insert(l); } Utils.Check(total == 0, "Transaction total not zero {0}", t); } } /// <summary> /// Set cleared status on other half of a transfer /// </summary> void setClearedStatus(Transaction t) { if (t.Journals.Count != 1 || string.IsNullOrEmpty(t.Cleared)) { return; } int acct = t.Journals[0].AccountId; if (acct > 0) { Account account = _module.Database.Get <Account>(acct); switch ((AcctType)account.AccountTypeId) { case AcctType.Bank: case AcctType.CreditCard: case AcctType.Investment: case AcctType.OtherAsset: case AcctType.OtherLiability: break; default: return; } Transaction other = _transactions.FirstOrDefault(o => o.AccountId == acct && o.DocumentDate == t.DocumentDate && o.Amount == -t.Amount && o.NameAddressId == t.NameAddressId && o.DocumentTypeId == (int)DocType.Transfer && o.Journals.Count == 1 && o.Journals[0].AccountId == t.AccountId); if (other != null) { other.Journals[0].Cleared = t.Cleared; } } } /// <summary> /// Skip to next ! command line /// </summary> void skip() { status("Skipping " + _line); while (getLine() && _line[0] != '!') { ; } } /// <summary> /// Set up transaction ready to process an investment /// </summary> void startInvestment() { _transaction = new Transaction(); _transaction.Line = Line; _transaction.AccountId = _account; _detail = new Journal(); _transaction.Journals.Add(_detail); _transaction.Stock = new StockTransaction(); } /// <summary> /// Set up transaction ready to process /// </summary> void startTransaction() { _transaction = new Transaction(); _transaction.Line = Line; _transaction.AccountId = _account; _detail = new Journal(); _transaction.Journals.Add(_detail); } /// <summary> /// Set batch status (if it is a batch) /// </summary> /// <param name="s"></param> void status(string s) { if (_module.Batch != null) { _module.Batch.Status = s; } }
/// <summary> /// Stock prices /// </summary> void importPrices() { status("Importing Prices"); while (getLine()) { switch (_tag) { case "!": return; case "^": // End of record getLine(); // Get next line for caller to process return; case "\"": string[] fields = _line.Split(','); string d = Utils.RemoveQuotes(fields[2]); StockPrice p = new StockPrice(); p.SecurityId = (int)_module.Database.ForeignKey("Security", "Ticker", Utils.RemoveQuotes(fields[0])); p.Price = double.Parse(fields[1]); p.Date = string.IsNullOrWhiteSpace(DateFormat) ? DateTime.Parse(d) : DateTime.ParseExact(d, DateFormat, System.Globalization.CultureInfo.InvariantCulture); _module.Database.Update(p);; break; default: throw new CheckException("Unexpected input:{0}", _line); } } }