Update_8_57.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. using com.sun.org.apache.xml.@internal.security.utils;
  2. using Comal.Classes;
  3. using InABox.Core;
  4. using InABox.Database;
  5. using Syncfusion.XlsIO.FormatParser.FormatTokens;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. namespace PRS.Shared.Database_Update_Scripts;
  12. internal class Update_8_57 : DatabaseUpdateScript
  13. {
  14. public override VersionNumber Version => new(8, 57);
  15. private void ApproveOldSetouts(IProvider provider)
  16. {
  17. Logger.Send(LogType.Information, "", "Approving all old setouts");
  18. var setouts = provider.Query(
  19. Filter<Setout>.Where(x => x.Status).IsEqualTo(SetoutStatus.Unapproved)
  20. .And(x => x.ID).NotInQuery(
  21. Filter<StagingSetout>.Where(x => x.Task.ID).IsNotEqualTo(Guid.Empty)
  22. .Or(x => x.UnapprovedDocuments).IsGreaterThan(0),
  23. x => x.Setout.ID),
  24. Columns.None<Setout>()
  25. .Add(x => x.ID)
  26. .Add(x => x.Status))
  27. .ToArray<Setout>()
  28. .ToQueue();
  29. var totalsetouts = setouts.Count;
  30. var processedsetouts = 0;
  31. while (setouts.Count > 0)
  32. {
  33. Logger.Send(LogType.Information, "", $"Updating {setouts.Count} staging setouts; {processedsetouts}/{totalsetouts}");
  34. var updates = setouts.Dequeue(100).ToArray();
  35. foreach(var update in updates)
  36. update.Status = SetoutStatus.Approved;
  37. provider.Save(updates);
  38. processedsetouts += updates.Length;
  39. };
  40. Logger.Send(LogType.Information, "", "Approving all old manufacturing packets");
  41. var packets = provider.Query(
  42. Filter<ManufacturingPacket>.Where(x => x.Approved).IsEqualTo(DateTime.MinValue),
  43. Columns.None<ManufacturingPacket>()
  44. .Add(x => x.ID)
  45. .Add(x => x.Approved)
  46. .Add(x => x.Created))
  47. .ToArray<ManufacturingPacket>()
  48. .ToQueue();
  49. var totalpackets = packets.Count;
  50. var processedpackets = 0;
  51. while (packets.Count > 0)
  52. {
  53. Logger.Send(LogType.Information, "", $"Updating {packets.Count} staging setouts; {processedpackets}/{totalpackets}");
  54. var updates = packets.Dequeue(100).ToArray();
  55. foreach(var update in updates)
  56. update.Approved = update.Created;
  57. provider.Save(updates);
  58. processedpackets += updates.Length;
  59. }
  60. }
  61. public override bool Update()
  62. {
  63. var provider = DbFactory.NewProvider(Logger.Main);
  64. ApproveOldSetouts(provider);
  65. var stagingSetoutsQueue = provider.Query(
  66. Filter<StagingSetout>.Where(x => x.Setout.ID).IsEqualTo(Guid.Empty)
  67. .Or(x => x.Task.ID).IsNotEqualTo(Guid.Empty)
  68. .Or(x => x.UnapprovedDocuments).IsGreaterThan(0),
  69. Columns.None<StagingSetout>()
  70. .Add(x => x.ID)
  71. .Add(x => x.Created)
  72. .Add(x => x.CreatedBy)
  73. .Add(x => x.Number)
  74. .Add(x => x.JobLink.ID)
  75. .Add(x => x.Group.ID)
  76. .Add(x => x.OriginalPath)
  77. .Add(x => x.OriginalCRC)
  78. .Add(x => x.SavePath)
  79. .Add(x => x.Archived)
  80. .Add(x => x.LockedBy.ID)
  81. .Add(x => x.Task.ID)
  82. .Add(x => x.Task.EmployeeLink.ID)
  83. .Add(x => x.Task.Title)
  84. .Add(x => x.Task.Description)
  85. .Add(x => x.Task.Notes)
  86. .Add(x => x.Task.Completed)
  87. .Add(x => x.JobScope.ID)
  88. .Add(x => x.Setout.ID))
  89. .ToArray<StagingSetout>()
  90. .ToQueue();
  91. Logger.Send(LogType.Information, "", $"Updating {stagingSetoutsQueue.Count} staging setouts");
  92. var total = stagingSetoutsQueue.Count;
  93. var processed = 0;
  94. while(stagingSetoutsQueue.Count > 0)
  95. {
  96. Logger.Send(LogType.Information, "", $"Updating {stagingSetoutsQueue.Count} staging setouts; {processed}/{total}");
  97. var stagingSetouts = stagingSetoutsQueue.Dequeue(100).ToArray();
  98. ProcessStagingSetouts(provider, stagingSetouts);
  99. processed += stagingSetouts.Length;
  100. }
  101. return true;
  102. }
  103. void ProcessStagingSetouts(IProvider provider, StagingSetout[] stagingSetouts)
  104. {
  105. var setoutIDs = stagingSetouts.ToArray(x => x.ID);
  106. var stagingSetoutDocuments = provider.Query(
  107. Filter<StagingSetoutDocument>.Where(x => x.EntityLink.ID).InList(setoutIDs),
  108. Columns.None<StagingSetoutDocument>()
  109. .Add(x => x.Approved)
  110. .Add(x => x.Notes)
  111. .Add(x => x.Superceded)
  112. .Add(x => x.Thumbnail)
  113. .Add(x => x.Type.ID)
  114. .Add(x => x.EntityLink.ID)
  115. .Add(x => x.DocumentLink.ID))
  116. .ToObjects<StagingSetoutDocument>()
  117. .GroupByDictionary(x => x.EntityLink.ID);
  118. var stagingSetoutForms = provider.Query(
  119. Filter<StagingSetoutForm>.Where(x => x.Parent.ID).InList(setoutIDs),
  120. Columns.None<StagingSetoutForm>()
  121. .Add(x => x.Parent.ID)
  122. .Add(x => x.Number)
  123. .Add(x => x.Description)
  124. .Add(x => x.Form.ID)
  125. .Add(x => x.FormData)
  126. .Add(x => x.BlobData)
  127. .Add(x => x.FormStarted)
  128. .Add(x => x.FormCompleted)
  129. .Add(x => x.FormProcessed)
  130. .Add(x => x.FormCancelled)
  131. .Add(x => x.FormCompletedBy.ID)
  132. .Add(x => x.Location.Address)
  133. .Add(x => x.Location.Latitude)
  134. .Add(x => x.Location.Longitude)
  135. .Add(x => x.Location.Timestamp)
  136. .Add(x => x.FormOpen)
  137. .Add(x => x.Sequence))
  138. .ToObjects<StagingSetoutForm>()
  139. .GroupByDictionary(x => x.Parent.ID);
  140. var stagingSetoutComponents = provider.Query(
  141. Filter<StagingSetoutComponent>.Where(x => x.StagingSetout.ID).InList(setoutIDs)
  142. .And(x => x.StagingManufacturingPacketComponent.ID).IsEqualTo(Guid.Empty),
  143. Columns.None<StagingSetoutComponent>()
  144. .Add(x => x.StagingSetout.ID)
  145. .Add(x => x.Product.ID)
  146. .Add(x => x.Description)
  147. .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Local)
  148. .Add(x => x.Quantity)
  149. .Add(x => x.Sequence))
  150. .ToObjects<StagingSetoutComponent>()
  151. .GroupByDictionary(x => x.StagingSetout.ID);
  152. var stagingManufacturingPackets = provider.Query(
  153. Filter<StagingManufacturingPacket>.Where(x => x.StagingSetout.ID).InList(setoutIDs),
  154. Columns.None<StagingManufacturingPacket>()
  155. .Add(x => x.ID)
  156. .Add(x => x.Title)
  157. .Add(x => x.Serial)
  158. .Add(x => x.ITP.ID)
  159. .Add(x => x.StagingSetout.ID)
  160. .Add(x => x.Watermark)
  161. .Add(x => x.Location)
  162. .Add(x => x.Quantity)
  163. .Add(x => x.BarcodeQuantity)
  164. .Add(x => x.Group.ID)
  165. .Add(x => x.Group.Watermark)
  166. .Add(x => x.Template.ID)
  167. .Add(x => x.ManufacturingPacket.ID))
  168. .ToObjects<StagingManufacturingPacket>()
  169. .GroupByDictionary(x => x.StagingSetout.ID);
  170. var manufacturingPackets = provider.Query(
  171. Filter<ManufacturingPacket>.Where(x => x.SetoutLink.ID).IsEqualTo(Guid.Empty)
  172. .And(x => x.ID).InQuery(
  173. Filter<StagingManufacturingPacket>.Where(x => x.StagingSetout.ID).InList(setoutIDs),
  174. x => x.ManufacturingPacket.ID),
  175. Columns.None<ManufacturingPacket>()
  176. .Add(x => x.ID)
  177. .Add(x => x.SetoutLink.ID))
  178. .ToObjects<ManufacturingPacket>()
  179. .ToDictionary(x => x.ID);
  180. var stagingManufacturingPacketComponents = provider.Query(
  181. Filter<StagingManufacturingPacketComponent>.Where(x => x.Packet.ID).InQuery(
  182. Filter<StagingManufacturingPacket>.Where(x => x.StagingSetout.ID).InList(setoutIDs),
  183. x => x.ID),
  184. Columns.None<StagingManufacturingPacketComponent>()
  185. .Add(x => x.Packet.ID)
  186. .Add(x => x.Description)
  187. .Add(x => x.Product.ID)
  188. .Add(x => x.Quantity)
  189. .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Local))
  190. .ToObjects<StagingManufacturingPacketComponent>()
  191. .GroupByDictionary(x => x.Packet.ID);
  192. var stagingManufacturingPacketStages = provider.Query(
  193. Filter<StagingManufacturingPacketStage>.Where(x => x.Packet.ID).InQuery(
  194. Filter<StagingManufacturingPacket>.Where(x => x.StagingSetout.ID).InList(setoutIDs),
  195. x => x.ID),
  196. Columns.None<StagingManufacturingPacketStage>()
  197. .Add(x => x.Packet.ID)
  198. .Add(x => x.Time)
  199. .Add(x => x.Sequence)
  200. .Add(x => x.SequenceType)
  201. .Add(x => x.QualityChecks)
  202. .Add(x => x.Section.ID))
  203. .ToObjects<StagingManufacturingPacketStage>()
  204. .GroupByDictionary(x => x.Packet.ID);
  205. var stagingManufacturingPacketTreatments = provider.Query(
  206. Filter<StagingManufacturingPacketTreatment>.Where(x => x.Packet.ID).InQuery(
  207. Filter<StagingManufacturingPacket>.Where(x => x.StagingSetout.ID).InList(setoutIDs),
  208. x => x.ID),
  209. Columns.None<StagingManufacturingPacketTreatment>()
  210. .Add(x => x.Packet.ID)
  211. .Add(x => x.Product.ID)
  212. .Add(x => x.Parameter))
  213. .ToObjects<StagingManufacturingPacketTreatment>()
  214. .GroupByDictionary(x => x.Packet.ID);
  215. var oldSetouts = provider.Query(
  216. Filter<Setout>.Where(x => x.ID).InList(stagingSetouts.ToArray(x => x.Setout.ID)),
  217. Columns.None<Setout>()
  218. .Add(x => x.ID))
  219. .ToObjects<Setout>()
  220. .ToDictionary(x => x.ID);
  221. var oldMap = new Dictionary<Setout, StagingSetout>();
  222. var setouts = new List<Setout>();
  223. var setoutDocuments = new Dictionary<Setout, List<SetoutDocument>>();
  224. var setoutForms = new Dictionary<Setout, List<SetoutForm>>();
  225. var components = new Dictionary<Setout, List<ManufacturingPacketComponent>>();
  226. var packets = new Dictionary<Setout, List<ManufacturingPacket>>();
  227. var packetComponents = new Dictionary<Setout, Dictionary<ManufacturingPacket, List<ManufacturingPacketComponent>>>();
  228. var packetStages = new Dictionary<ManufacturingPacket, List<ManufacturingPacketStage>>();
  229. var packetTreatments = new Dictionary<ManufacturingPacket, List<ManufacturingTreatment>>();
  230. foreach(var stagingSetout in stagingSetouts)
  231. {
  232. if(stagingSetout.Setout.ID == Guid.Empty
  233. || !oldSetouts.TryGetValue(stagingSetout.Setout.ID, out var setout))
  234. {
  235. setout = new Setout();
  236. setout.Created = stagingSetout.Created;
  237. setout.CreatedBy = stagingSetout.CreatedBy;
  238. setout.Number = stagingSetout.Number;
  239. setout.JobLink.ID = stagingSetout.JobLink.ID;
  240. setout.Group.ID = stagingSetout.Group.ID;
  241. setout.Status = SetoutStatus.Unapproved;
  242. setout.JobScope.ID = stagingSetout.JobScope.ID;
  243. }
  244. else
  245. {
  246. }
  247. if (oldMap.TryAdd(setout, stagingSetout))
  248. {
  249. setouts.Add(setout);
  250. }
  251. if(stagingSetoutDocuments.TryGetValue(stagingSetout.ID, out var documents))
  252. {
  253. var newSetoutDocuments = setoutDocuments.GetValueOrAdd(setout);
  254. if(documents.All(x => x.Approved))
  255. {
  256. setout.Status = SetoutStatus.Approved;
  257. }
  258. foreach(var stagingSetoutDocument in documents)
  259. {
  260. var setoutDocument = new SetoutDocument();
  261. setoutDocument.DocumentLink.ID = stagingSetoutDocument.DocumentLink.ID;
  262. setoutDocument.Type.ID = stagingSetoutDocument.Type.ID;
  263. setoutDocument.Thumbnail = stagingSetoutDocument.Thumbnail;
  264. setoutDocument.Superceded = stagingSetoutDocument.Superceded;
  265. setoutDocument.Notes = stagingSetoutDocument.Notes;
  266. setoutDocument.Staging.OriginalCRC = stagingSetout.OriginalCRC;
  267. setoutDocument.Staging.OriginalPath = stagingSetout.OriginalPath;
  268. setoutDocument.Staging.SavePath = stagingSetout.SavePath;
  269. setoutDocument.Staging.LockedBy.ID = stagingSetout.LockedBy.ID;
  270. newSetoutDocuments.Add(setoutDocument);
  271. }
  272. }
  273. if(stagingSetout.Task.ID != Guid.Empty)
  274. {
  275. setout.Status = SetoutStatus.Cancelled;
  276. setout.Problem.AssignedTo.ID = stagingSetout.Task.EmployeeLink.ID;
  277. var notes = new List<string>()
  278. {
  279. stagingSetout.Task.Title,
  280. stagingSetout.Task.Description,
  281. };
  282. if (stagingSetout.Task.Notes != null)
  283. notes.AddRange(stagingSetout.Task.Notes);
  284. setout.Problem.Notes = notes.ToArray();
  285. setout.Problem.Resolved = stagingSetout.Task.Completed;
  286. }
  287. if(stagingSetoutForms.TryGetValue(stagingSetout.ID, out var forms))
  288. {
  289. var newSetoutForms = setoutForms.GetValueOrAdd(setout);
  290. foreach(var form in forms)
  291. {
  292. var newForm = new SetoutForm();
  293. newForm.Number = form.Number;
  294. newForm.Description = form.Description;
  295. newForm.Form.ID = form.Form.ID;
  296. newForm.FormData = form.FormData;
  297. newForm.BlobData = form.BlobData;
  298. newForm.FormStarted = form.FormStarted;
  299. newForm.FormCompleted = form.FormCompleted;
  300. newForm.FormProcessed = form.FormProcessed;
  301. newForm.FormCancelled = form.FormCancelled;
  302. newForm.FormCompletedBy.ID = form.FormCompletedBy.ID;
  303. newForm.Location.CopyFrom(form.Location);
  304. newForm.FormOpen = form.FormOpen;
  305. newForm.Sequence = form.Sequence;
  306. newSetoutForms.Add(newForm);
  307. }
  308. }
  309. if(stagingSetoutComponents.TryGetValue(stagingSetout.ID, out var componentsList))
  310. {
  311. var newComponents = components.GetValueOrAdd(setout);
  312. foreach(var component in componentsList)
  313. {
  314. var newComponent = new ManufacturingPacketComponent();
  315. newComponent.Product.ID = component.Product.ID;
  316. newComponent.Description = component.Description;
  317. newComponent.Dimensions.CopyFrom(component.Dimensions);
  318. newComponent.Quantity = component.Quantity;
  319. newComponent.Sequence = component.Sequence;
  320. newComponents.Add(newComponent);
  321. }
  322. }
  323. if(stagingManufacturingPackets.TryGetValue(stagingSetout.ID, out var stagingPackets))
  324. {
  325. var newPackets = packets.GetValueOrAdd(setout);
  326. var newSetoutPacketComponents = packetComponents.GetValueOrAdd(setout);
  327. foreach(var stagingPacket in stagingPackets)
  328. {
  329. if(stagingPacket.ManufacturingPacket.ID != Guid.Empty)
  330. {
  331. if(manufacturingPackets.TryGetValue(stagingPacket.ManufacturingPacket.ID, out var oldPacket))
  332. {
  333. newPackets.Add(oldPacket);
  334. }
  335. }
  336. else
  337. {
  338. var newPacket = new ManufacturingPacket();
  339. newPacket.Title = stagingPacket.Title;
  340. newPacket.Serial = stagingPacket.Serial;
  341. newPacket.ITP.ID = stagingPacket.ITP.ID;
  342. newPacket.WaterMark = stagingPacket.Watermark.NotWhiteSpaceOr(stagingPacket.Group.Watermark);
  343. newPacket.Location = stagingPacket.Location;
  344. newPacket.Quantity = stagingPacket.Quantity;
  345. newPacket.BarcodeQty = stagingPacket.BarcodeQuantity.IsNullOrWhiteSpace()
  346. ? stagingPacket.Quantity
  347. : int.Parse(stagingPacket.BarcodeQuantity);
  348. newPacket.TemplateGroup.ID = stagingPacket.Group.ID;
  349. newPacket.ManufacturingTemplateLink.ID = stagingPacket.Template.ID;
  350. newPackets.Add(newPacket);
  351. if(stagingManufacturingPacketComponents.TryGetValue(stagingPacket.ID, out var stagingComponents))
  352. {
  353. var newPacketComponents = new List<ManufacturingPacketComponent>();
  354. newSetoutPacketComponents.Add(newPacket, newPacketComponents);
  355. foreach(var stagingComponent in stagingComponents)
  356. {
  357. var component = new ManufacturingPacketComponent();
  358. component.Description = stagingComponent.Description;
  359. component.Product.ID = stagingComponent.Product.ID;
  360. component.Quantity = stagingComponent.Quantity;
  361. component.Dimensions.CopyFrom(stagingComponent.Dimensions);
  362. newPacketComponents.Add(component);
  363. }
  364. }
  365. if(stagingManufacturingPacketStages.TryGetValue(stagingPacket.ID, out var stagingStages))
  366. {
  367. var newStages = new List<ManufacturingPacketStage>();
  368. packetStages.Add(newPacket, newStages);
  369. foreach(var stagingStage in stagingStages)
  370. {
  371. var stage = new ManufacturingPacketStage
  372. {
  373. Time = stagingStage.Time,
  374. Sequence = stagingStage.Sequence,
  375. SequenceType = stagingStage.SequenceType,
  376. Started = DateTime.MinValue,
  377. PercentageComplete = 0.0F,
  378. Completed = DateTime.MinValue,
  379. QualityChecks = stagingStage.QualityChecks,
  380. QualityStatus = QualityStatus.NotChecked,
  381. QualityNotes = ""
  382. };
  383. stage.ManufacturingSectionLink.ID = stagingStage.Section.ID;
  384. newStages.Add(stage);
  385. }
  386. }
  387. if(stagingManufacturingPacketTreatments.TryGetValue(stagingPacket.ID, out var stagingTreatments))
  388. {
  389. var newTreatments = new List<ManufacturingTreatment>();
  390. packetTreatments.Add(newPacket, newTreatments);
  391. foreach(var stagingTreatment in stagingTreatments)
  392. {
  393. var treatment = new ManufacturingTreatment();
  394. treatment.Product.ID = stagingTreatment.Product.ID;
  395. treatment.Parameter = stagingTreatment.Parameter;
  396. newTreatments.Add(treatment);
  397. }
  398. }
  399. }
  400. }
  401. }
  402. }
  403. provider.Save(setouts);
  404. foreach(var setout in setouts)
  405. {
  406. if(oldMap.TryGetValue(setout, out var stagingSetout))
  407. {
  408. stagingSetout.Setout.ID = setout.ID;
  409. }
  410. if(setoutDocuments.TryGetValue(setout, out var documents))
  411. {
  412. foreach(var document in documents)
  413. {
  414. document.EntityLink.ID = setout.ID;
  415. }
  416. }
  417. if(setoutForms.TryGetValue(setout, out var forms))
  418. {
  419. foreach(var form in forms)
  420. {
  421. form.Parent.ID = setout.ID;
  422. }
  423. }
  424. if(components.TryGetValue(setout, out var setoutComponents))
  425. {
  426. foreach(var component in setoutComponents)
  427. {
  428. component.Setout.ID = setout.ID;
  429. }
  430. }
  431. if(packets.TryGetValue(setout, out var setoutPackets))
  432. {
  433. var setoutPacketComponents = packetComponents.GetValueOrDefault(setout);
  434. foreach(var packet in setoutPackets)
  435. {
  436. packet.SetoutLink.ID = setout.ID;
  437. }
  438. }
  439. }
  440. provider.Save(stagingSetouts);
  441. provider.Save(setoutDocuments.SelectMany(x => x.Value).Where(x => x.EntityLink.ID != Guid.Empty));
  442. provider.Save(setoutForms.SelectMany(x => x.Value).Where(x => x.Parent.ID != Guid.Empty));
  443. provider.Save(packets.SelectMany(x => x.Value).Where(x => x.SetoutLink.ID != Guid.Empty));
  444. foreach(var (setout, setoutPackets) in packets)
  445. {
  446. var setoutComponents = packetComponents.GetValueOrDefault(setout);
  447. foreach(var packet in setoutPackets)
  448. {
  449. if (packet.SetoutLink.ID == Guid.Empty) continue;
  450. if(setoutComponents is not null
  451. && setoutComponents.TryGetValue(packet, out var manufacturingPacketComponents))
  452. {
  453. foreach(var component in manufacturingPacketComponents)
  454. {
  455. component.Setout.ID = setout.ID;
  456. component.Packet.ID = packet.ID;
  457. }
  458. }
  459. if(packetStages.TryGetValue(packet, out var stages))
  460. {
  461. foreach(var stage in stages)
  462. {
  463. stage.Parent.ID = packet.ID;
  464. }
  465. }
  466. if(packetTreatments.TryGetValue(packet, out var treatments))
  467. {
  468. foreach(var treatment in treatments)
  469. {
  470. treatment.Packet.ID = packet.ID;
  471. }
  472. }
  473. }
  474. }
  475. provider.Save(components.SelectMany(x => x.Value).Where(x => x.Setout.ID != Guid.Empty)
  476. .Concat(packetComponents.SelectMany(x => x.Value).SelectMany(x => x.Value).Where(x => x.Packet.ID != Guid.Empty && x.Setout.ID != Guid.Empty)));
  477. provider.Save(packetStages.SelectMany(x => x.Value).Where(x => x.Parent.ID != Guid.Empty));
  478. provider.Save(packetTreatments.SelectMany(x => x.Value).Where(x => x.Packet.ID != Guid.Empty));
  479. }
  480. }