DataUtils.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Threading.Tasks;
  7. using System.Windows;
  8. using System.Windows.Forms;
  9. using Comal.Classes;
  10. using InABox.Clients;
  11. using InABox.Configuration;
  12. using InABox.Core;
  13. using InABox.Database;
  14. using InABox.Database.SQLite;
  15. using InABox.DynamicGrid;
  16. using InABox.WPF;
  17. using Org.BouncyCastle.Math.EC.Multiplier;
  18. using Syncfusion.Windows.Controls;
  19. using MessageBox = System.Windows.MessageBox;
  20. namespace PRSDesktop
  21. {
  22. public class Utility
  23. {
  24. //private void UpgradeShipmentLinks(Entity[] notifications)
  25. //{
  26. // int i = 1;
  27. // foreach (DeliveryNotification notification in notifications)
  28. // {
  29. // Progress.SetMessage(String.Format("Converting Delivery Notifications {0} / {1}", i, notifications.Length));
  30. // notification.ShipmentLink = new ShipmentLink();
  31. // if (notification.Shipment != null)
  32. // {
  33. // notification.ShipmentLink.ID = notification.Shipment.ID;
  34. // notification.Shipment = null;
  35. // }
  36. // i++;
  37. // }
  38. //}
  39. private static bool HasDocumentLinks<T>()
  40. {
  41. var props = typeof(T).GetProperties().Where(x =>
  42. x.PropertyType.Equals(typeof(DocumentLink)) || x.PropertyType.Equals(typeof(ImageDocumentLink)) ||
  43. x.PropertyType.Equals(typeof(PDFDocumentLink)));
  44. return props.Any();
  45. }
  46. private static Guid[] GetDocuments<T>(T entity)
  47. {
  48. var result = new List<Guid>();
  49. var props = typeof(T).GetProperties().Where(x =>
  50. x.PropertyType.Equals(typeof(DocumentLink)) || x.PropertyType.Equals(typeof(ImageDocumentLink)) ||
  51. x.PropertyType.Equals(typeof(PDFDocumentLink)));
  52. foreach (var prop in props)
  53. {
  54. var link = (IEntityLink)prop.GetValue(entity);
  55. if (link.IsValid())
  56. result.Add(link.ID);
  57. }
  58. return result.ToArray();
  59. }
  60. //private static bool CopyType<T>(int typeno, int typecount, IProvider source, IProvider target) where T : Entity, new()
  61. //{
  62. // String name = typeof(T).EntityName().Split('.').Last();
  63. // //if (!HasDocumentLinks<T>())
  64. // // return false;
  65. // Progress.SetMessage(String.Format("[{0}/{1}] {2}: Loading Source Items..", typeno, typecount, name));
  66. // var sourceitems = source.Load<T>();
  67. // Progress.SetMessage(String.Format("[{0}/{1}] {2}: Loading Target Items..", typeno, typecount, name));
  68. // var targetitems = target.Load<T>();
  69. // //if (sourceitems.Count() == targetitems.Count())
  70. // // return false;
  71. // //Progress.SetMessage(String.Format("[{0}/{1}] {2}: Deleting Target Items..", typeno, typecount, name));
  72. // //foreach (var targetitem in targetitems)
  73. // // target.Delete(targetitem);
  74. // for (int i=0; i<sourceitems.Length; i++)
  75. // {
  76. // Progress.SetMessage(String.Format("[{0}/{1}] {2}: Copying Items ({3:F2}% complete)..", typeno, typecount, name, (double)i * 100.0F / (double)sourceitems.Length));
  77. // var sourceitem = sourceitems[i];
  78. // if (ClientFactory.IsSupported<AuditTrail>())
  79. // {
  80. // var audits = source.Load<AuditTrail>(new Filter<AuditTrail>(x => x.EntityID).IsEqualTo(sourceitem.ID));
  81. // foreach (var audit in audits)
  82. // target.Save(audit);
  83. // }
  84. // if (sourceitem is IEntityDocument)
  85. // {
  86. // var entdoc = (IEntityDocument)sourceitem;
  87. // if (entdoc.DocumentLink.ID != Guid.Empty)
  88. // {
  89. // var doc = source.Load(new Filter<Document>(x => x.ID).IsEqualTo(entdoc.DocumentLink.ID)).FirstOrDefault();
  90. // if (doc != null)
  91. // target.Save(doc);
  92. // else
  93. // entdoc.DocumentLink.ID = Guid.Empty;
  94. // }
  95. // }
  96. // Guid[] docids = GetDocuments<T>(sourceitem);
  97. // foreach (var docid in docids)
  98. // {
  99. // var doc = source.Load(new Filter<Document>(x => x.ID).IsEqualTo(docid)).FirstOrDefault();
  100. // if (doc != null)
  101. // target.Save(doc);
  102. // }
  103. // target.Delete(sourceitem);
  104. // target.Save(sourceitem);
  105. // }
  106. // target.CommitTransaction();
  107. // return true;
  108. // #region oldcode
  109. // //open.Invoke(target, new object[] { "Duplicate", true });
  110. // ////if (items.Length != orig.Count)
  111. // //{
  112. // // Progress.SetMessage(string.Format("{0}/{1} {2}: Clearing..", t + 1, types.Count, type.Name));
  113. // // for (int i = 0; i < orig.Count; i++)
  114. // // {
  115. // // //Progress.SetMessage(string.Format("{0}/{1} {2}: Resetting ({3:F2}% complete)..", t + 1, types.Length, type.Name, (double)i * 100.0F / (double)orig.Count));
  116. // // delete.Invoke(target, new object[] { orig[i] });
  117. // // }
  118. // // Progress.SetMessage(string.Format("{0}/{1} {2}: Rebuilding..", t + 1, types.Count, type.Name));
  119. // // for (int i = 0; i < items.Count; i++)
  120. // // {
  121. // // //if (i > 10)
  122. // // // return;
  123. // // var item = items[i];
  124. // // //double progress = (double)i * 100.0F / (double)items.Length;
  125. // // ////Progress.SetMessage(string.Format("{0}/{1} {2}: Copying ({3:F2}% complete)..", t + 1, types.Length, type.Name, progress));
  126. // // //// Check and copy source document if required
  127. // // //if (item is IEntityDocument)
  128. // // //{
  129. // // // var entdoc = (IEntityDocument)item;
  130. // // // var doccli = new RemoteClient<Document>(URL, Port);
  131. // // // doccli.UserID = "FROGSOFTWARE";
  132. // // // doccli.Password = "FROGSOFTWARE";
  133. // // // //Progress.SetMessage(string.Format("{0}/{1} {2}: Copying (Documents)", t + 1, types.Length, type.Name));
  134. // // // var docfilter = new Filter<Document>(x => x.ID).IsEqualTo(entdoc.DocumentLink.ID);
  135. // // // var document = doccli.Load(docfilter).FirstOrDefault(); ;
  136. // // // if (document != null)
  137. // // // target.Save(document);
  138. // // //}
  139. // // //Progress.SetMessage(string.Format("{0}/{1} {2}: Copying ({3:F2}% complete).. (Saving)", t + 1, types.Length, type.Name, progress));
  140. // // save.Invoke(target, new object[] { item });
  141. // // //Dictionary<String, Object> values = item.GetValues(true);
  142. // // //var member = CoreUtils.GetMemberExpression(type, "ID");
  143. // // //var filter = Activator.CreateInstance(typeof(Filter<>).MakeGenericType(type));
  144. // // //CoreUtils.SetPropertyValue(filter, "Expression", member);
  145. // // //CoreUtils.SetPropertyValue(filter, "Operator", Operator.IsEqualTo);
  146. // // //CoreUtils.SetPropertyValue(filter, "Value", item.ID);
  147. // // //BaseObject[] compare = (BaseObject[])(load.Invoke(provider, new object[] { filter, null }));
  148. // // //BaseObject newitem = compare.FirstOrDefault();
  149. // // //if (newitem != null)
  150. // // //{
  151. // // // var changes = newitem.Compare(values);
  152. // // // if (changes.Any())
  153. // // // throw new Exception(String.Format("Object Values have changed!\n\n{0}", String.Join("\n", changes)));
  154. // // //}
  155. // // }
  156. // //}
  157. // //target.CommitTransaction();
  158. // //close.Invoke(target, new object[] { "Duplicate", true });
  159. // #endregion
  160. //}
  161. private static List<string> CompareType<T>(int typeno, int typecount, IProvider source, IProvider target) where T : Entity, new()
  162. {
  163. var result = new List<string>();
  164. var name = typeof(T).EntityName().Split('.').Last();
  165. Progress.SetMessage(string.Format("[{0}/{1}] {2}: Reloading Source Table..", typeno, typecount, name));
  166. //var items = local.Load();
  167. var sourcetable = source.Query<T>();
  168. Progress.SetMessage(string.Format("[{0}/{1}] {2}: Reloading Target Table..", typeno, typecount, name));
  169. var targettable = target.Query<T>();
  170. for (var i = 0; i < sourcetable.Rows.Count; i++)
  171. {
  172. Progress.SetMessage(string.Format("[{0}/{1}] {2}: Comparing Values ({3:F2}% complete)..", typeno, typecount, name,
  173. (double)i * 100.0F / sourcetable.Rows.Count));
  174. var sourcerow = sourcetable.Rows[i];
  175. var id = sourcerow.Get<Guid>("ID");
  176. var targetrow = targettable.Rows.FirstOrDefault(r => r.Get<Guid>("ID").Equals(id));
  177. if (targetrow == null)
  178. result.Add(string.Format("{0}: Row [{1}] is missing in target database", name, id));
  179. else
  180. foreach (var col in targettable.Columns)
  181. {
  182. var targetvalue = targetrow[col.ColumnName];
  183. var sourcevalue = sourcerow[col.ColumnName];
  184. if (targetvalue == null)
  185. {
  186. if (sourcevalue != null)
  187. result.Add(string.Format("{0}: Row [{1}].{2} is null in target, but [{3}] in source", name, id, col.ColumnName,
  188. sourcevalue));
  189. }
  190. else if (!targetvalue.Equals(sourcevalue))
  191. {
  192. result.Add(string.Format("{0}: Row [{1}].{2} is [{3}] in target, but [{4}] in source", name, id, col.ColumnName,
  193. targetvalue,
  194. sourcevalue));
  195. }
  196. }
  197. }
  198. return result;
  199. }
  200. private static void LoadType(Type type, List<Type> into, Type[] exclude)
  201. {
  202. if (exclude.Contains(type) || into.Contains(type))
  203. return;
  204. var props = type.GetProperties().Where(x => x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink)));
  205. if (!props.Any())
  206. {
  207. into.Insert(0, type);
  208. }
  209. else
  210. {
  211. foreach (var prop in props)
  212. {
  213. var subtype = prop.PropertyType.BaseType.GetGenericArguments().First();
  214. if (subtype != type)
  215. LoadType(subtype, into, exclude);
  216. }
  217. into.Add(type);
  218. }
  219. }
  220. public static void DuplicateDatabase()
  221. {
  222. using (var ofd = new OpenFileDialog())
  223. {
  224. ofd.Filter = "SQLite Database Files (*.dbs)|*.dbs";
  225. ofd.DefaultExt = "dbs";
  226. ofd.InitialDirectory = Path.GetDirectoryName(DbFactory.ProviderFactory.URL);
  227. ofd.FileName = "";
  228. ofd.Multiselect = false;
  229. ofd.CheckFileExists = true;
  230. var result = ofd.ShowDialog();
  231. if (result != DialogResult.OK || string.IsNullOrWhiteSpace(ofd.FileName))
  232. return;
  233. BaseObject.GlobalObserving = false;
  234. var source = new SQLiteProviderFactory(ofd.FileName);
  235. Progress.Show("Opening Source Database");
  236. source.Types = DbFactory.ProviderFactory.Types;
  237. source.Start();
  238. try
  239. {
  240. var types = CoreUtils.TypeList(
  241. AppDomain.CurrentDomain.GetAssemblies(),
  242. x =>
  243. x.IsClass
  244. && !x.IsGenericType
  245. && x.IsSubclassOf(typeof(Entity))
  246. && !x.Equals(typeof(AuditTrail))
  247. && x.Equals(typeof(Setout))
  248. && x.GetInterfaces().Contains(typeof(IRemotable))
  249. );
  250. var orderedtypes = new List<Type>();
  251. foreach (var type in types)
  252. LoadType(type, orderedtypes,
  253. new[] { typeof(Document), /* typeof(Comal.Classes.Calendar), */ typeof(Email), typeof(GPSTrackerLocation) });
  254. var results = new List<string>();
  255. orderedtypes = orderedtypes.Where(x => x.Equals(typeof(Setout))).ToList();
  256. for (var i = 0; i < orderedtypes.Count; i++)
  257. {
  258. var type = orderedtypes[i];
  259. var copy = typeof(Utility).GetMethod("CopyType", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(type);
  260. var copied = (bool)copy.Invoke(null, new object[] { i, orderedtypes.Count, source, DbFactory.ProviderFactory });
  261. if (copied)
  262. {
  263. var compare = typeof(Utility).GetMethod("CompareType", BindingFlags.Static | BindingFlags.NonPublic)
  264. .MakeGenericMethod(type);
  265. compare.Invoke(null, new object[] { i, orderedtypes.Count, source, DbFactory.ProviderFactory });
  266. }
  267. }
  268. File.WriteAllText("compare.text", string.Join("\n", results));
  269. Progress.Close();
  270. MessageBox.Show("All Done");
  271. }
  272. catch (Exception e)
  273. {
  274. Progress.Close();
  275. MessageBox.Show("Import Failed!\n\n" + e.Message + "\n\n" + e.StackTrace);
  276. }
  277. BaseObject.GlobalObserving = true;
  278. }
  279. }
  280. private static void EmptyStores(params Type[] entities)
  281. {
  282. foreach (var entity in entities)
  283. {
  284. var client = ClientFactory.CreateClient(entity);
  285. try
  286. {
  287. var items = client.Load();
  288. if (items != null)
  289. foreach (var item in items)
  290. client.Delete(item, "Emptying Store");
  291. }
  292. catch (Exception e)
  293. {
  294. throw new Exception(string.Format("{1}\nType: {0}", entity.Name, e.Message));
  295. }
  296. }
  297. }
  298. private static void EmptyStores()
  299. {
  300. var entities = CoreUtils.TypeList(
  301. new[]
  302. {
  303. typeof(Setout).Assembly
  304. },
  305. myType =>
  306. myType.IsClass
  307. && !myType.IsAbstract
  308. && !myType.IsGenericType
  309. && myType.IsSubclassOf(typeof(Entity))
  310. && myType.GetInterfaces().Contains(typeof(IPersistent))
  311. ).ToArray();
  312. EmptyStores(entities);
  313. }
  314. public static string[] ProcessNotes(string[] notes, string description)
  315. {
  316. var Notes = notes != null ? notes.ToList() : new List<string>();
  317. if (!string.IsNullOrWhiteSpace(description) && !description.Equals("Enter Description of Task Here"))
  318. {
  319. var bFound = false;
  320. for (var i = 0; i < Notes.Count; i++)
  321. if (!string.IsNullOrWhiteSpace(Notes[i]) && Notes[i].Contains(description))
  322. {
  323. Notes[i] = description;
  324. bFound = true;
  325. }
  326. if (!bFound)
  327. Notes.Insert(0, description);
  328. }
  329. return Notes.Select(x => CoreUtils.StripHTML(x)).ToArray();
  330. }
  331. public static void SetupColumns()
  332. {
  333. var usercolumns = new DynamicGridColumns
  334. {
  335. new() { ColumnName = "UserID", Width = 0, Caption = "User ID" },
  336. new() { ColumnName = "Password", Width = 0, Caption = "Password" }
  337. };
  338. new GlobalConfiguration<DynamicGridColumns>(typeof(User).Name).Save(usercolumns);
  339. var empcolumns = new DynamicGridColumns
  340. {
  341. new() { ColumnName = "Code", Width = 200, Caption = "Code" },
  342. new() { ColumnName = "Name", Width = 0, Caption = "Name" },
  343. new() { ColumnName = "CanAllocateTasks", Width = 40, Caption = "Tasks?" },
  344. new() { ColumnName = "PayrollID", Width = 200, Caption = "Payroll ID" }
  345. };
  346. new GlobalConfiguration<DynamicGridColumns>(typeof(Employee).Name).Save(empcolumns);
  347. var jobcolumns = new DynamicGridColumns
  348. {
  349. new() { ColumnName = "Number", Width = 50, Caption = " Job #", /* Type = typeof(int), */ Alignment = Alignment.MiddleCenter },
  350. new() { ColumnName = "Name", Width = 0, Caption = " Name" /* , Type = typeof(String) */ }
  351. };
  352. new GlobalConfiguration<DynamicGridColumns>(typeof(Job).Name).Save(jobcolumns);
  353. var setoutcolumns = new DynamicGridColumns
  354. {
  355. new() { ColumnName = "Number", Width = 80 /* , Type = typeof(String) */ },
  356. new() { ColumnName = "Title", Width = 200 /* , Type = typeof(String) */ },
  357. new() { ColumnName = "Description", Width = 0 /* , Type = typeof(String) */ },
  358. new() { ColumnName = "Quantity", Width = 50, /* Type=typeof(int), */ Caption = "Qty", Alignment = Alignment.MiddleCenter },
  359. new() { ColumnName = "Status", Width = 0 /* , Type = typeof(String) */ },
  360. new() { ColumnName = "DueDate", Width = 60, /* Type = typeof(DateTime), */ Format = "dd/MM/yy", Alignment = Alignment.MiddleCenter },
  361. new()
  362. {
  363. ColumnName = "Forecast.ManufacturingDate", Width = 60, /* Type = typeof(DateTime), */ Caption = "Est Date", Format = "dd/MM/yy",
  364. Alignment = Alignment.MiddleCenter
  365. }
  366. };
  367. new GlobalConfiguration<DynamicGridColumns>(typeof(Setout).Name).Save(setoutcolumns);
  368. var deliverycolumns = new DynamicGridColumns
  369. {
  370. new() { ColumnName = "Barcode", Width = 100 /* , Type = typeof(String) */ },
  371. new() { ColumnName = "Setout.Job.Name", Width = 200 /* , Type = typeof(String) */ },
  372. new() { ColumnName = "Title", Width = 0 /* , Type = typeof(String) */ },
  373. new() { ColumnName = "Setout.Quantity", Width = 50, /* Type=typeof(int), */ Caption = "Qty", Alignment = Alignment.MiddleCenter },
  374. new() { ColumnName = "Setout.Description", Width = 0 /* , Type = typeof(String) */ },
  375. new()
  376. {
  377. ColumnName = "DueDate", Width = 60, /* Type = typeof(DateTime), */ Caption = "Due Date", Format = "dd/MM/yy",
  378. Alignment = Alignment.MiddleCenter
  379. },
  380. new()
  381. {
  382. ColumnName = "Setout.Forecast.ManufacturingDate", Width = 60, /* Type = typeof(DateTime), */ Caption = "Est Date",
  383. Format = "dd/MM/yy", Alignment = Alignment.MiddleCenter
  384. },
  385. new()
  386. {
  387. ColumnName = "ManufacturedDate", Width = 60, /* Type = typeof(DateTime), */ Caption = "Ready", Format = "dd/MM/yy",
  388. Alignment = Alignment.MiddleCenter
  389. },
  390. new() { ColumnName = "Setout.Status", Width = 150 /* , Type = typeof(String) */ }
  391. };
  392. new GlobalConfiguration<DynamicGridColumns>(typeof(DeliveryItem).Name).Save(deliverycolumns);
  393. var shipmentcolumns = new DynamicGridColumns
  394. {
  395. new() { ColumnName = "Code", Width = 80, /* Type = typeof(String), */ Alignment = Alignment.MiddleCenter },
  396. new() { ColumnName = "Description", Width = 0 /* , Type = typeof(String) */ }
  397. };
  398. new GlobalConfiguration<DynamicGridColumns>(typeof(Shipment).Name).Save(shipmentcolumns);
  399. var employeecolumns = new DynamicGridColumns
  400. {
  401. new() { ColumnName = "Code", Width = 120 /* , Type = typeof(String) */ },
  402. new() { ColumnName = "Name", Width = 0 /* , Type = typeof(String) */ },
  403. new() { ColumnName = "Address.Street", Width = 0 /* , Type = typeof(String) */ },
  404. new() { ColumnName = "Address.City", Width = 150 /* , Type = typeof(String) */ },
  405. new() { ColumnName = "Type.Name", Width = 120 /* , Type = typeof(String) */ },
  406. new()
  407. {
  408. ColumnName = "StartDate", Width = 60, /* Type = typeof(DateTime), */ Caption = "Started", Format = "dd/MM/yy",
  409. Alignment = Alignment.MiddleCenter
  410. },
  411. new()
  412. {
  413. ColumnName = "FinishDate", Width = 60, /* Type = typeof(DateTime), */ Caption = "Finished", Format = "dd/MM/yy",
  414. Alignment = Alignment.MiddleCenter
  415. }
  416. };
  417. new GlobalConfiguration<DynamicGridColumns>(typeof(Employee).Name).Save(employeecolumns);
  418. var customercolumns = new DynamicGridColumns
  419. {
  420. new() { ColumnName = "Code", Width = 200 /* , Type = typeof(String) */ },
  421. new() { ColumnName = "Name", Width = 0 /* , Type = typeof(String) */ },
  422. new() { ColumnName = "Delivery.Street", Width = 0 /* , Type = typeof(String) */ },
  423. new() { ColumnName = "Delivery.City", Width = 150 /* , Type = typeof(String) */ }
  424. };
  425. new GlobalConfiguration<DynamicGridColumns>(typeof(Customer).Name).Save(customercolumns);
  426. var gpstrackercolumns = new DynamicGridColumns
  427. {
  428. new() { ColumnName = "DeviceID", Width = 200 /* , Type = typeof(String) */ },
  429. new() { ColumnName = "Description", Width = 0 /* , Type = typeof(String) */ },
  430. new()
  431. {
  432. ColumnName = "Location.Latitude", Width = 100, /* Type = typeof(double), */ Caption = "Latitude", Format = "F6",
  433. Alignment = Alignment.MiddleCenter
  434. },
  435. new()
  436. {
  437. ColumnName = "Location.Longitude", Width = 100, /* Type = typeof(double), */ Caption = "Longitude", Format = "F6",
  438. Alignment = Alignment.MiddleCenter
  439. },
  440. new()
  441. {
  442. ColumnName = "Location.Timestamp", Width = 100, /* Type = typeof(DateTime), */ Caption = "Last Update",
  443. Format = "dd/MM/yy HH:mm",
  444. Alignment = Alignment.MiddleCenter
  445. }
  446. };
  447. new GlobalConfiguration<DynamicGridColumns>(typeof(GPSTracker).Name).Save(gpstrackercolumns);
  448. }
  449. private class RequisitionItemLine
  450. {
  451. public Guid ID { get; private set; }
  452. public InvoiceLine Line { get; private set; }
  453. public CostCentre CostCentre { get; private set; }
  454. public double? Charge { get; set; }
  455. public RequisitionItemLine(Guid id, CostCentre costcentre, String description, double? charge)
  456. {
  457. ID = id;
  458. Line = new InvoiceLine() { Description = description };
  459. CostCentre = costcentre;
  460. Charge = charge;
  461. }
  462. }
  463. //public void InvoiceTimeSheets()
  464. //{
  465. // TimeSheet[] times = new Client<TimeSheet>().Load(
  466. // new Filter<TimeSheet>(x => x.Processed).IsEqualTo(DateTime.MinValue).And(x => x.Approved).IsNotEqualTo(DateTime.MinValue).And(x => x.InvoiceLink.ID).IsEqualTo(Guid.Empty).And(x => x.JobLink.ID).IsNotEqualTo(Guid.Empty)
  467. // );
  468. // List<Job> jobs = new List<Job>();
  469. // foreach (var time in times)
  470. // {
  471. // if (!jobs.Contains(time.JobLink.ID))
  472. // jobs.Add(time.JobLink.ID);
  473. // }
  474. // foreach (Guid jobid in jobs)
  475. // {
  476. // Invoice invoice = new Invoice();
  477. // invoice.JobLink.ID = jobid;
  478. // }
  479. //}
  480. }
  481. }