public AjaxReturn BatchStatus(int id) { AjaxReturn result = new AjaxReturn(); BatchJob batch = AppModule.GetBatchJob(id); if (batch == null) { Log("Invalid batch id"); result.error = "Invalid batch id"; } else { if (batch == null) { Log("Invalid batch id"); result.error = "Invalid batch id"; } else { Log("Batch {0}:{1}%:{2}", batch.Id, batch.PercentComplete, batch.Status); result.data = batch; if (batch.Finished) { result.error = batch.Error; result.redirect = batch.Redirect; Log("Batch finished - redirecting to {0}", batch.Redirect); } } } return(result); }
/// <summary> /// Ensure a record matching a doc type exists /// </summary> void ensureDocTypeExists(DocType enumValue, string nameType, int?primaryAccountid) { Table table = TableFor("DocumentType"); JObject d = new JObject().AddRange(table.PrimaryKey.Name, (int)enumValue, table.Indexes[1].Fields[0].Name, enumValue.UnCamel(), "NameType", nameType, "Sign", AppModule.SignFor(enumValue), "PrimaryAccountId", primaryAccountid); updateIfChanged(table, d); }
/// <summary> /// Set up import, import the data, commit to the database if no errors /// </summary> public void Import(CsvParser csv, AppModule module) { lock (this) { _module = module; if (!string.IsNullOrEmpty(TableName)) { _table = _module.Database.TableFor(TableName); } _keys = new HashSet <string>(); ImportData(csv); _module.Database.Commit(); } }
/// <summary> /// Import a bank statement, and return it (no posting is made to the database) /// </summary> public JArray ImportTransactions(TextReader r, AppModule module) { lock (this) { JArray result = new JArray(); _transactionsOnly = true; _reader = r; _module = module; Line = 0; Character = 0; _accountsProcessed = new List <int>(); _transactions = new List <Transaction>(); if (!getLine()) { return(result); } while (!_eof) { switch (_line) { case "!Type:Cash": case "!Type:Bank": importTransactions(DocType.Withdrawal, DocType.Deposit); break; case "!Type:CCard": importTransactions(DocType.CreditCardCharge, DocType.CreditCardCredit); break; default: skip(); break; } } // Now copy wanted data to the output foreach (Transaction t in _transactions) { JObject j = new JObject(); j["Name"] = string.IsNullOrEmpty(t.Name) ? t.DocumentMemo : t.Name; j["Amount"] = t.Amount; j["Date"] = t.DocumentDate; if (!string.IsNullOrEmpty(t.DocumentIdentifier)) { j["Id"] = t.DocumentIdentifier; } j["Memo"] = t.DocumentMemo; result.Add(j); } return(result); } }
/// <summary> /// Update a journal line /// </summary> public override void Update(JObject dataOut) { if (dataOut["AccountId"] == null) { return; // Can't post if no account } int id = dataOut.AsInt("idDocument"); if (id == 0) { return; // Can't post if no document } bool newTran = id != _tranId; DocType docType = (DocType)dataOut.AsInt("DocumentTypeId"); if (newTran) { // New document _vat = 0; _vatAmount = 0; dataOut["DocumentAddress"] = string.Join("\r\n", Enumerable.Range(1, 5).Select(i => dataOut.AsString("Address" + i)).Where(s => !string.IsNullOrEmpty(s)).ToArray()); if (!_module.Database.RecordExists("Document", dataOut.AsInt("idDocument"))) { dataOut["VatPaid"] = 0; } base.Update(dataOut); // Save the document _tranId = id; _line = 0; // Save the last invoice/cheque/etc. no int number = Utils.ExtractNumber(dataOut.AsString("DocumentIdentifier")); switch (docType) { case DocType.Invoice: case DocType.CreditMemo: if (number > _lastInvoiceNumber) { _lastInvoiceNumber = number; } break; case DocType.Bill: case DocType.Credit: if (number > _lastBillNumber) { _lastBillNumber = number; } break; case DocType.Withdrawal: case DocType.CreditCardCharge: registerNumber(_lastChequeNumber, dataOut.AsInt("AccountId"), number); break; case DocType.Deposit: case DocType.CreditCardCredit: registerNumber(_lastDepositNumber, dataOut.AsInt("AccountId"), number); break; case DocType.GeneralJournal: if (number > _lastJournalNumber) { _lastJournalNumber = number; } break; } // Delete any existing lines _module.Database.Execute("DELETE FROM Line WHERE idLine IN (SELECT idJournal FROM Journal WHERE DocumentId = " + _tranId + ")"); _module.Database.Execute("DELETE FROM Journal WHERE DocumentId = " + _tranId); } dataOut["DocumentId"] = _tranId; dataOut["JournalNum"] = ++_line; dataOut["Memo"] = dataOut["DocumentMemo"]; _module.Database.Update("Journal", dataOut); // Save the journal if (dataOut.AsInt("AccountId") == (int)Acct.VATControl) { // This is the VAT journal _vatAmount += dataOut.AsDecimal("Amount"); if (_vat != 0) { // There is already a VAT journal - delete it _module.Database.Execute("DELETE FROM Line WHERE idLine IN (SELECT idJournal FROM Journal WHERE DocumentId = " + _tranId + " AND JournalNum = " + _vat + ")"); _module.Database.Execute("DELETE FROM Journal WHERE DocumentId = " + _tranId + " AND JournalNum = " + _vat); _module.Database.Execute("UPDATE Journal SET JournalNum = JournalNum - 1 WHERE DocumentId = " + _tranId + " AND JournalNum > " + _vat); // Bump this journal a line earlier dataOut["JournalNum"] = --_line; dataOut["Amount"] = _vatAmount; _module.Database.Update("Journal", dataOut); } _vat = _line; // Remember, to avoid 2 VAT lines } // 2nd and subsequent journals (except VAT journal) have lines // NB VAT Payments to HMRC have are exceptions - they have a line for the VAT payment if (!newTran && (_line == 2 || dataOut.AsInt("AccountId") != (int)Acct.VATControl)) { int sign = AppModule.SignFor(docType); dataOut["idLine"] = dataOut["idJournal"]; dataOut["LineAmount"] = sign * dataOut.AsDecimal("Amount"); dataOut["Qty"] = sign * dataOut.AsDecimal("Qty"); dataOut["VatRate"] = dataOut.AsDecimal("VatRate"); dataOut["VatAmount"] = sign * dataOut.AsDecimal("VatAmount"); _module.Database.Update("Line", dataOut); } }
/// <summary> /// Action a job /// </summary> public AjaxReturn JobAction(int id) { AjaxReturn ret = new AjaxReturn(); Schedule job = Database.Get <Schedule>(id); Utils.Check(job.idSchedule != null, "Job {0} not found", id); if (!string.IsNullOrWhiteSpace(job.Url)) { // Job actually does something if (job.Post) { // It posts a record string methodName = job.Url; string moduleName = Utils.NextToken(ref methodName, "/"); Type type = AppModule.GetModule(moduleName); Utils.Check(type != null, "Invalid schedule job {0}", job.Url); AppModule module = (AppModule)Activator.CreateInstance(type); module.Context = Context; module.OriginalModule = module.Module = moduleName.ToLower(); module.OriginalMethod = module.Method = (string.IsNullOrEmpty(methodName) ? "default" : Path.GetFileNameWithoutExtension(methodName)).ToLower(); module.GetParameters = new NameValueCollection(); module.Parameters["json"] = job.Parameters; module.Parameters["date"] = job.ActionDate; MethodInfo method; object o = module.CallMethod(out method); if (method == null) { ret.error = "Job url not found " + job.Url; } else if (method.ReturnType == typeof(AjaxReturn)) { ret = o as AjaxReturn; if (ret.error == null && ret.redirect != null) { ret.redirect += "&from=" + HttpUtility.UrlEncode(Parameters.AsString("from")); } ret.id = null; } else { throw new CheckException("Unexpected return type {0}", method.ReturnType.Name); } } else { // It just redirects somewhere ret.redirect = Path.ChangeExtension(job.Url, ".html") + "?id=" + id; } } if (string.IsNullOrEmpty(ret.error)) { // Update job to say it is done switch ((RepeatType)job.RepeatType) { case RepeatType.None: // No repeat - delete job Database.Delete(job); ret.message = "Job deleted"; return(ret); case RepeatType.Daily: job.ActionDate = job.ActionDate.AddDays(job.RepeatFrequency); while (job.ActionDate.DayOfWeek == DayOfWeek.Saturday || job.ActionDate.DayOfWeek == DayOfWeek.Sunday) { job.ActionDate = job.ActionDate.AddDays(1); } break; case RepeatType.Weekly: job.ActionDate = job.ActionDate.AddDays(7 * job.RepeatFrequency); break; case RepeatType.Monthly: job.ActionDate = job.ActionDate.AddMonths(job.RepeatFrequency); break; case RepeatType.Quarterly: job.ActionDate = job.ActionDate.AddMonths(3 * job.RepeatFrequency); break; case RepeatType.Yearly: job.ActionDate = job.ActionDate.AddYears(job.RepeatFrequency); break; default: throw new CheckException("Invalid repeat type {0}", job.RepeatType); } Database.Update(job); } ret.id = job.idSchedule; return(ret); }
public ImportBatchJob(AppModule module, FileProcessor file, Action action) : base(module, action) { _file = file; }
/// <summary> /// Process a single request /// </summary> /// <param name="listenerContext"></param> void ProcessRequest(object listenerContext) { DateTime started = DateTime.Now; // For timing response HttpListenerContext context = null; AppModule module = null; StringBuilder log = new StringBuilder(); // Session log writes to here, and it is displayed at the end try { context = (HttpListenerContext)listenerContext; log.AppendFormat("{0} {1}:{2}:[ms]:", context.Request.RemoteEndPoint.Address, context.Request.Headers["X-Forwarded-For"], context.Request.RawUrl); Session session = null; string filename = HttpUtility.UrlDecode(context.Request.Url.AbsolutePath).Substring(1); if (filename == "") { filename = "company"; // Default page is Company } string moduleName = null; string methodName = null; string baseName = filename.Replace(".html", ""); // Ignore .html - treat as a program request if (baseName.IndexOf(".") < 0) { // Urls of the form /ModuleName[/MethodName][.html] call a C# AppModule string[] parts = baseName.Split('/'); if (parts.Length <= 2) { Type type = AppModule.GetModule(parts[0]); if (type != null) { // The AppModule exists - create the object module = (AppModule)Activator.CreateInstance(type); moduleName = parts[0]; if (parts.Length == 2) { methodName = parts[1]; } } } } if (moduleName == null) { // No AppModule found - treat url as a file request moduleName = "FileSender"; module = new FileSender(filename); } // AppModule found - retrieve or create a session for it Cookie cookie = context.Request.Cookies["session"]; if (cookie != null) { _sessions.TryGetValue(cookie.Value, out session); if (AppSettings.Default.SessionLogging) { log.AppendFormat("[{0}{1}]", cookie.Value, session == null ? " not found" : ""); } } if (session == null) { if (moduleName == "FileSender") { session = new Session(null); } else { session = new Session(this); cookie = new Cookie("session", session.Cookie, "/"); if (AppSettings.Default.SessionLogging) { log.AppendFormat("[{0} new session]", cookie.Value); } } } if (cookie != null) { context.Response.Cookies.Add(cookie); cookie.Expires = session.Expires = Utils.Now.AddHours(1); } // Set up module module.Session = session; module.LogString = log; if (moduleName.EndsWith("Module")) { moduleName = moduleName.Substring(0, moduleName.Length - 6); } using (module) { // Call method module.Call(context, moduleName, methodName); } } catch (Exception ex) { while (ex is TargetInvocationException) { ex = ex.InnerException; } if (ex is System.Net.Sockets.SocketException) { log.AppendFormat("Request error: {0}\r\n", ex.Message); } else { log.AppendFormat("Request error: {0}\r\n", ex); if (module == null || !module.ResponseSent) { try { module = new AppModule(); module.Session = _empty; module.LogString = log; module.Context = context; module.Module = "exception"; module.Method = "default"; module.Title = "Exception"; module.Exception = ex; module.WriteResponse(module.Template("exception", module), "text/html", HttpStatusCode.InternalServerError); } catch (Exception ex1) { log.AppendFormat("Error displaying exception: {0}\r\n", ex1); if (module == null || !module.ResponseSent) { try { module.WriteResponse("Error displaying exception:" + ex.Message, "text/plain", HttpStatusCode.InternalServerError); } catch { } } } } } } if (context != null) { try { context.Response.Close(); } catch { } } try { Log(log.ToString().Replace(":[ms]:", ":" + Math.Round((DateTime.Now - started).TotalMilliseconds, 0) + " ms:")); } catch { } }