-
Notifications
You must be signed in to change notification settings - Fork 4
/
Company.cs
219 lines (205 loc) · 7.45 KB
/
Company.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Reflection;
using System.IO;
using System.Web;
using Newtonsoft.Json.Linq;
namespace AccountServer {
/// <summary>
/// For Scheduled transactions
/// </summary>
enum RepeatType {
None, Daily, Weekly, Monthly, Quarterly, Yearly
}
/// <summary>
/// Company front page, and todo list (including scheduled transactions)
/// </summary>
public class Company : AppModule {
public Company() {
Menu = new MenuOption[] {
new MenuOption("Summary", "/company/default.html"),
new MenuOption("To Do", "/company/schedule.html"),
new MenuOption("New To Do", "/company/job.html?id=0")
};
}
public override void Default() {
Record = new JObject().AddRange(
"schedule", DefaultScheduleListing(),
"banking", total(Database.Query("Account.*, AcctType, SUM(Amount) AS Balance",
"WHERE AccountTypeId " + Database.In(AcctType.Bank, AcctType.CreditCard)
+ " AND DocumentDate <= " + Database.Quote(Utils.Today)
+ " AND HideAccount != 1 GROUP BY idAccount ORDER BY AccountTypeId, AccountName",
"Account", "Journal", "Document"), "AcctType", "Balance"),
"investments", total(Database.Query(@"SELECT Account.*, Amount AS CashBalance, Value
FROM (SELECT AccountId, SUM(Amount) AS Amount FROM Journal GROUP BY AccountId) AS Balances
JOIN Account ON idAccount = Balances.AccountId
JOIN AccountType ON idAccountType = AccountTypeId
LEFT JOIN (" + Investments.AccountValue(Utils.Today) + @") AS AccountValues ON AccountValues.ParentAccountId = Balances.AccountId
WHERE AccountTypeId = " + (int)AcctType.Investment + @"
AND (Amount <> 0 OR Value <> 0)
GROUP BY idAccount ORDER BY AccountName"), "Name", "CashBalance", "Value"),
"customer", total(Database.Query(@"SELECT NameAddress.*, Sum(Outstanding) AS Outstanding
FROM NameAddress
LEFT JOIN Journal ON NameAddressId = idNameAddress
AND AccountId = " + (int)Acct.SalesLedger + @"
WHERE Type='C'
AND Outstanding <> 0
GROUP BY idNameAddress
ORDER BY Name
"), "Name", "Outstanding"),
"supplier", total(Database.Query(@"SELECT NameAddress.*, Sum(Outstanding) AS Outstanding
FROM NameAddress
LEFT JOIN Journal ON NameAddressId = idNameAddress
AND AccountId = " + (int)Acct.PurchaseLedger + @"
WHERE Type='S'
AND Outstanding <> 0
GROUP BY idNameAddress
ORDER BY Name
"), "Name", "Outstanding")
);
}
public object DefaultScheduleListing() {
return Database.Query("SELECT idSchedule, ActionDate, RepeatType, RepeatFrequency, Task, Post, CASE WHEN ActionDate <= " + Database.Quote(Utils.Today) + " THEN 'due' ELSE NULL END AS \"@class\" FROM Schedule WHERE ActionDate <= "
+ Database.Quote(Utils.Today.AddDays(7)) + " ORDER BY ActionDate");
}
public decimal NetWorth;
public void Schedule() {
}
public object ScheduleListing() {
return Database.Query("SELECT idSchedule, ActionDate, RepeatType, RepeatFrequency, Task, Post FROM Schedule ORDER BY ActionDate");
}
/// <summary>
/// Get a todo job for editing
/// </summary>
public void Job(int id) {
Schedule job = Database.Get<Schedule>(id);
if (job.idSchedule == null) {
job.ActionDate = Utils.Today;
}
Record = job;
}
public AjaxReturn JobSave(Schedule json) {
Utils.Check(json.RepeatFrequency > 0, "Repeat frequency must be > 0");
return SaveRecord(json, false);
}
public AjaxReturn JobDelete(int id) {
AjaxReturn result = new AjaxReturn();
try {
Database.Delete("Schedule", id, false);
result.message = "Job deleted";
} catch {
result.error = "Cannot delete";
}
return result;
}
/// <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;
}
/// <summary>
/// Select all items with a value in one of the field names.
/// If there was at least one, add a total row at the bottom, with each fieldname set to its total,
/// and totalFieldName set to the total of all them.
/// Also add the grand total into NetWorth.
/// </summary>
IEnumerable<JObject> total(IEnumerable<JObject> list, string totalFieldName, params string[] fieldnames) {
bool addTotal = false;
decimal[] totals = new decimal[fieldnames.Length];
foreach (JObject j in list) {
bool include = false;
for (int i = 0; i < fieldnames.Length; i++) {
decimal d = j.AsDecimal(fieldnames[i]);
totals[i] += d;
if (d != 0)
include = true;
}
if (include) {
yield return j;
addTotal = true;
}
}
JObject tot = new JObject();
tot["@class"] = "total";
tot[totalFieldName] = "Total";
for (int i = 0; i < fieldnames.Length; i++) {
tot[fieldnames[i]] = totals[i];
NetWorth += totals[i];
}
if(addTotal)
yield return tot;
}
}
}