stgGather.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. unit stgGather;
  2. interface
  3. uses
  4. Classes, stgGatherCacheData, ProjectData, BillsTree, sdIDTree;
  5. type
  6. TProgramHintEvent = procedure (const ATenderName: string) of Object;
  7. TstgSumBaseFileLoader = class
  8. private
  9. FTree: TstgGatherTree;
  10. FSumBaseFile: string;
  11. FTempFolder: string;
  12. FFileName: string;
  13. FProjectData: TProjectData;
  14. procedure LoadFileName;
  15. function LoadTreeNodeData(ANode: TBillsIDTreeNode; AParent: TstgGatherTreeNode): TstgGatherTreeNode;
  16. procedure LoadSumBaseTreeNode(ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode);
  17. public
  18. constructor Create(ATree: TstgGatherTree; const ASumBaseFile: string);
  19. destructor Destroy; override;
  20. procedure LoadData;
  21. end;
  22. TstgSubTenderFileGather = class
  23. private
  24. FCacheData: TstgGatherCacheData;
  25. FProjectData: TProjectData;
  26. FCurSubTenderID: Integer;
  27. FLoadHint: TProgramHintEvent;
  28. procedure GatherDetailData(AGatherNode: TstgGatherTreeNode; ASourceNode: TMeasureBillsIDTreeNode);
  29. function GatherSubTenderTreeNodeData(ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode): TstgGatherTreeNode;
  30. procedure GatherSubTenderTreeNode(ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode);
  31. procedure GatherSubTender(ASubTenderID: Integer);
  32. public
  33. procedure GatherTo(AGatherCacheData: TstgGatherCacheData; ASubTenders: TList);
  34. property LoadHint: TProgramHintEvent read FLoadHint write FLoadHint;
  35. end;
  36. TstgErrorChecker = class
  37. private
  38. FCacheData: TstgGatherCacheData;
  39. procedure NewError(ANode: TstgGatherTreeNode; AType: Integer);
  40. function SafeCheckParent(ANode, ACheckParent: TstgGatherTreeNode): TstgGatherTreeNode;
  41. // ACheckParent的子项(总包中存在),存在与ANode同编号节点
  42. function HasSameCodeLevelChild(ANode: TstgGatherTreeNode;
  43. ACheckParent: tstgGatherTreeNode = nil): Boolean;
  44. // ACheckParent的子项(总包中存在),存在与ANode同编号、名称、单位,但不同层次节点
  45. function HasSameChildWithDiffLevel(ANode: TstgGatherTreeNode;
  46. ACheckParent: TstgGatherTreeNode = nil): Boolean;
  47. // ACheckParent的子项(总包中存在)(含子项的子项),存在与ANode同编号节点
  48. // 子项(含子项的子项),存在与CheckParent的子项(总包中存在)同编号节点
  49. function HasShortRelaCodeChild(ANode: TstgGatherTreeNode): Boolean;
  50. function HasLongRelaCodeChild(ANode:TstgGatherTreeNode): Boolean;
  51. function HasXmjChildWithSameCodeChild(ANode: TstgGatherTreeNode): Boolean;
  52. procedure AddXmjError(ANode: TstgGatherTreeNode);
  53. procedure AddGclError(ANode: TstgGatherTreeNode);
  54. procedure AddError(ANode: TstgGatherTreeNode);
  55. public
  56. procedure Check(AGatherCacheData: TstgGatherCacheData);
  57. end;
  58. implementation
  59. uses Math, Globals, mDataRecord, UtilMethods, SysUtils, XMLDoc, XMLIntf,
  60. CacheTree;
  61. { TstgSumBaseFileLoader }
  62. constructor TstgSumBaseFileLoader.Create(ATree: TstgGatherTree;
  63. const ASumBaseFile: string);
  64. begin
  65. FTree := ATree;
  66. FSumBaseFile := ASumBaseFile;
  67. FTempFolder := GenerateTempFolder(GetTempFilePath);
  68. FProjectData := TProjectData.Create;
  69. end;
  70. destructor TstgSumBaseFileLoader.Destroy;
  71. begin
  72. if FileExists(FTempFolder) then
  73. DeleteFolder(FTempFolder);
  74. if Assigned(FProjectData) then
  75. FProjectData.Free;
  76. inherited;
  77. end;
  78. procedure TstgSumBaseFileLoader.LoadData;
  79. begin
  80. UnZipFile(FSumBaseFile, FTempFolder);
  81. LoadFileName;
  82. FProjectData.OpenForSumUpBase(FTempFolder + '\' + FFileName);
  83. LoadSumBaseTreeNode(FProjectData.BillsCompileData.BillsCompileTree.FirstNode, nil);
  84. FTree.MarkLeafXmj;
  85. end;
  86. procedure TstgSumBaseFileLoader.LoadFileName;
  87. var
  88. FXmlDocument: IXMLDocument;
  89. RootXmlNode, InfoXmlNode: IXMLNode;
  90. ChildNodes: IXMLNodeList;
  91. begin
  92. FXmlDocument := TXMLDocument.Create(nil) as IXMLDocument;
  93. try
  94. FXmlDocument.LoadFromFile(FTempFolder + '\Info.xml');
  95. FXmlDocument.Options := [doNodeAutoCreate,doNodeAutoIndent,doAutoPrefix,doNamespaceDecl];
  96. RootXmlNode := FXmlDocument.DocumentElement;
  97. ChildNodes := RootXmlNode.ChildNodes;
  98. InfoXmlNode := ChildNodes.FindNode('ProjectInfo');
  99. FFileName := InfoXmlNode.Attributes['FileName'];
  100. finally
  101. FXmlDocument := nil;
  102. end;
  103. end;
  104. procedure TstgSumBaseFileLoader.LoadSumBaseTreeNode(ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode);
  105. var
  106. vCurGatherNode: TstgGatherTreeNode;
  107. begin
  108. if not Assigned(ANode) then Exit;
  109. vCurGatherNode := LoadTreeNodeData(TBillsIDTreeNode(ANode), AParent);
  110. LoadSumBaseTreeNode(ANode.FirstChild, vCurGatherNode);
  111. LoadSumBaseTreeNode(ANode.NextSibling, AParent);
  112. end;
  113. function TstgSumBaseFileLoader.LoadTreeNodeData(ANode: TBillsIDTreeNode;
  114. AParent: TstgGatherTreeNode): TstgGatherTreeNode;
  115. begin
  116. Result := FTree.AddSumBaseNode(AParent, ANode.ID);
  117. Result.Code := ANode.Rec.Code.AsString;
  118. Result.B_Code := ANode.Rec.B_Code.AsString;
  119. Result.Name := ANode.Rec.Name.AsString;
  120. Result.Units := ANode.Rec.Units.AsString;
  121. Result.IsLeaf := not ANode.HasChildren;
  122. end;
  123. { TstgSubTenderFileGather }
  124. procedure TstgSubTenderFileGather.GatherDetailData(
  125. AGatherNode: TstgGatherTreeNode; ASourceNode: TMeasureBillsIDTreeNode);
  126. var
  127. vSubTender: TstgSubTenderStageData;
  128. begin
  129. //if Assigned(ASourceNode.StageRec) and
  130. // ((ASourceNode.StageRec.GatherQuantity.AsFloat <> 0) or (ASourceNode.StageRec.GatherTotalPrice.AsFloat <> 0)) then
  131. //if not ASourceNode.HasChildren then
  132. if (AGatherNode.IsSubTender) or (not ASourceNode.HasChildren) then
  133. begin
  134. vSubTender := AGatherNode.SafeSubTender(FCurSubTenderID);
  135. vSubTender.AddDetail(ASourceNode);
  136. end;
  137. end;
  138. procedure TstgSubTenderFileGather.GatherSubTender(ASubTenderID: Integer);
  139. var
  140. vNode: TsdIDTreeNode;
  141. begin
  142. FCurSubTenderID := ASubTenderID;
  143. vNode := ProjectManager.ProjectsTree.FindNode(ASubTenderID);
  144. if vNode.Rec.ValueByName('Type').AsInteger = 1 then
  145. begin;
  146. FLoadHint(vNode.Rec.ValueByName('Name').AsString);
  147. FProjectData := OpenProjectManager.FindProjectData(ASubTenderID);
  148. try
  149. if not Assigned(FProjectData) then
  150. begin
  151. FProjectData := TProjectData.Create;
  152. FProjectData.OpenForSumUpGather(GetMyProjectsFilePath + vNode.Rec.ValueByName('FileName').AsString);
  153. end;
  154. FCacheData.AddSubTender(vNode.Rec);
  155. GatherSubTenderTreeNode(FProjectData.BillsMeasureData.BillsMeasureTree.FirstNode, nil);
  156. finally
  157. if not Assigned(OpenProjectManager.FindProjectData(ASubTenderID)) then
  158. FProjectData.Free;
  159. end;
  160. end;
  161. end;
  162. procedure TstgSubTenderFileGather.GatherSubTenderTreeNode(
  163. ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode);
  164. var
  165. vCur: TstgGatherTreeNode;
  166. begin
  167. if not Assigned(ANode) then Exit;
  168. vCur := GatherSubTenderTreeNodeData(ANode, AParent);
  169. GatherSubTenderTreeNode(ANode.FirstChild, vCur);
  170. GatherSubTenderTreeNode(ANode.NextSibling, AParent);
  171. end;
  172. function TstgSubTenderFileGather.GatherSubTenderTreeNodeData(
  173. ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode): TstgGatherTreeNode;
  174. var
  175. vNode: TMeasureBillsIDTreeNode;
  176. vNext: TstgGatherTreeNode;
  177. begin
  178. vNode := TMeasureBillsIDTreeNode(ANode);
  179. if ANode.ID < 100 then
  180. Result := FCacheData.GatherTree.FindNode(ANode.ID)
  181. else
  182. Result := FCacheData.GatherTree.FindNode(AParent, vNode);
  183. if not Assigned(Result) then
  184. begin
  185. vNext := FCacheData.GatherTree.FindNextSibling(AParent, vNode.Rec.Code.AsString, vNode.Rec.B_Code.AsString);
  186. if not Assigned(AParent) or (not (AParent.IsSumBase and AParent.IsLeafXmj)) or (vNode.Rec.B_Code.AsString <> '') {or (not ANode.HasChildren)} then
  187. begin
  188. if ANode.ID < 100 then
  189. Result := FCacheData.GatherTree.AddSubTenderNode(AParent, vNext, ANode.ID)
  190. else
  191. Result := FCacheData.GatherTree.AddSubTenderNode(AParent, vNext);
  192. Result.Code := Trim(vNode.Rec.Code.AsString);
  193. Result.B_Code := Trim(vNode.Rec.B_Code.AsString);
  194. Result.Name := Trim(vNode.Rec.Name.AsString);
  195. Result.Units := Trim(vNode.Rec.Units.AsString);
  196. Result.IsLeaf := not vNode.HasChildren;
  197. end
  198. else
  199. Result := AParent;
  200. end;
  201. if Assigned(Result) then
  202. GatherDetailData(Result, vNode)
  203. else
  204. Result := AParent;
  205. end;
  206. procedure TstgSubTenderFileGather.GatherTo(AGatherCacheData: TstgGatherCacheData;
  207. ASubTenders: TList);
  208. var
  209. i, iSubTenderID: Integer;
  210. begin
  211. FCacheData := AGatherCacheData;
  212. for i := 0 to ASubTenders.Count - 1 do
  213. GatherSubTender(Integer(ASubTenders.Items[i]));
  214. FCacheData.GatherTree.CalculateAll;
  215. end;
  216. { TstgErrorChecker }
  217. procedure TstgErrorChecker.AddError(ANode: TstgGatherTreeNode);
  218. begin
  219. if ANode.IsGclBills then
  220. AddGclError(ANode)
  221. else
  222. AddXmjError(ANode);
  223. end;
  224. procedure TstgErrorChecker.AddGclError(ANode: TstgGatherTreeNode);
  225. begin
  226. if HasXmjChildWithSameCodeChild(ANode) then
  227. NewError(ANode, iErrorXmjLess)
  228. else if HasLongRelaCodeChild(ANode) then
  229. NewError(ANode, iErrorGclMore)
  230. else if HasShortRelaCodeChild(ANode) then
  231. NewError(ANode, iErrorGclLess)
  232. else if HasSameChildWithDiffLevel(ANode) then
  233. NewError(ANode, iErrorGclMore)
  234. else if HasSameCodeLevelChild(ANode) then
  235. NewError(ANode, iErrorGclDiff)
  236. else
  237. NewError(ANode, iErrorGclAdd);
  238. end;
  239. procedure TstgErrorChecker.AddXmjError(ANode: TstgGatherTreeNode);
  240. begin
  241. if HasSameCodeLevelChild(ANode) then
  242. NewError(ANode, iErrorXmjDiff)
  243. else
  244. NewError(ANode, iErrorXmjAdd);
  245. end;
  246. procedure TstgErrorChecker.Check(AGatherCacheData: TstgGatherCacheData);
  247. var
  248. i: Integer;
  249. vNode, vParent: TstgGatherTreeNode;
  250. begin
  251. FCacheData := AGatherCacheData;
  252. for i := 0 to FCacheData.GatherTree.CacheNodes.Count - 1 do
  253. begin
  254. vNode := TstgGatherTreeNode(FCacheData.GatherTree.CacheNodes[i]);
  255. vParent := TstgGatherTreeNode(vNode.Parent);
  256. if vNode.IsSubTender and (not Assigned(vParent) or not vParent.IsSubTender) then
  257. AddError(vNode);
  258. end;
  259. end;
  260. function TstgErrorChecker.HasLongRelaCodeChild(
  261. ANode: TstgGatherTreeNode): Boolean;
  262. var
  263. vParent, vChild: TstgGatherTreeNode;
  264. i: Integer;
  265. begin
  266. Result := False;
  267. vParent := SafeCheckParent(ANode, nil);
  268. for i := 0 to vParent.Children.Count - 1 do
  269. begin
  270. vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
  271. if (Pos(ANode.B_Code + '-', vChild.B_Code) = 1) and (vChild.IsSumBase) then
  272. begin
  273. Result := True;
  274. Break;
  275. end;
  276. end;
  277. end;
  278. function TstgErrorChecker.HasSameChildWithDiffLevel(ANode,
  279. ACheckParent: TstgGatherTreeNode): Boolean;
  280. var
  281. vParent, vChild: TstgGatherTreeNode;
  282. i: Integer;
  283. begin
  284. Result := False;
  285. vParent := SafeCheckParent(ANode, ACheckParent);
  286. for i := 0 to vParent.Children.Count - 1 do
  287. begin
  288. vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
  289. if vChild.IsSumBase and (vChild.Code = ANode.Code) and
  290. (vChild.B_Code = ANode.B_Code) and (vChild.Name = ANode.Name) and
  291. (vChild.Units = ANode.Units) and (vChild.IsLeaf = vChild.IsLeaf) then
  292. begin
  293. Result := True;
  294. Break;
  295. end;
  296. end;
  297. end;
  298. function TstgErrorChecker.HasSameCodeLevelChild(ANode,
  299. ACheckParent: tstgGatherTreeNode): Boolean;
  300. var
  301. vParent, vChild: TstgGatherTreeNode;
  302. i: Integer;
  303. begin
  304. Result := False;
  305. vParent := SafeCheckParent(ANode, ACheckParent);
  306. for i := 0 to vParent.Children.Count - 1 do
  307. begin
  308. vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
  309. if vChild.IsSumBase and (vChild.Code = ANode.Code) and (vChild.B_Code = ANode.B_Code) and (vChild.IsLeaf = vChild.IsLeaf) then
  310. begin
  311. Result := True;
  312. Break;
  313. end;
  314. end;
  315. end;
  316. function TstgErrorChecker.HasShortRelaCodeChild(
  317. ANode: TstgGatherTreeNode): Boolean;
  318. var
  319. vParent, vChild: TstgGatherTreeNode;
  320. i: Integer;
  321. begin
  322. Result := False;
  323. vParent := SafeCheckParent(ANode, nil);
  324. for i := 0 to vParent.Children.Count - 1 do
  325. begin
  326. vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
  327. if (Pos(vChild.B_Code + '-', ANode.B_Code) = 1) and (vChild.IsSumBase) then
  328. begin
  329. Result := True;
  330. Break;
  331. end;
  332. end;
  333. end;
  334. function TstgErrorChecker.HasXmjChildWithSameCodeChild(
  335. ANode: TstgGatherTreeNode): Boolean;
  336. var
  337. vParent, vChild: TstgGatherTreeNode;
  338. i: Integer;
  339. begin
  340. Result := False;
  341. vParent := SafeCheckParent(ANode, nil);
  342. for i := 0 to vParent.Children.Count - 1 do
  343. begin
  344. vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
  345. if not vChild.IsGclBills and ANode.IsGclBills and vChild.IsSumBase then
  346. begin
  347. Result := True;
  348. Break;
  349. end;
  350. end;
  351. end;
  352. procedure TstgErrorChecker.NewError(ANode: TstgGatherTreeNode;
  353. AType: Integer);
  354. procedure RecursiveNewError(AParent: TstgGatherTreeNode);
  355. var
  356. i: Integer;
  357. begin
  358. if AParent.Children.Count > 0 then
  359. begin
  360. for i := 0 to AParent.Children.Count - 1 do
  361. RecursiveNewError(TstgGatherTreeNode(AParent.Children.Items[i]));
  362. end
  363. else
  364. FCacheData.AddError(ANode, AParent, AType);
  365. end;
  366. begin
  367. RecursiveNewError(ANode);
  368. end;
  369. function TstgErrorChecker.SafeCheckParent(ANode,
  370. ACheckParent: TstgGatherTreeNode): TstgGatherTreeNode;
  371. begin
  372. if Assigned(ACheckParent) then
  373. Result := ACheckParent
  374. else if Assigned(ANode.Parent) then
  375. Result := TstgGatherTreeNode(ANode.Parent)
  376. else
  377. Result := TstgGatherTreeNode(FCacheData.GatherTree.Root);
  378. end;
  379. end.