BillsCompileDm.pas 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  1. unit BillsCompileDm;
  2. interface
  3. uses
  4. BillsDm, StandardBillsFme,
  5. SysUtils, Classes, sdDB, BillsTree, sdIDTree;
  6. type
  7. TBillsCompileData = class(TDataModule)
  8. sdvBillsCompile: TsdDataView;
  9. procedure sdvBillsCompileGetText(var Text: String;
  10. ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
  11. DisplayText: Boolean);
  12. procedure sdvBillsCompileAfterValueChanged(AValue: TsdValue);
  13. procedure sdvBillsCompileBeforeValueChange(AValue: TsdValue;
  14. const NewValue: Variant; var Allow: Boolean);
  15. procedure sdvBillsCompileSetText(var Text: String;
  16. ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
  17. var Allow: Boolean);
  18. procedure sdvBillsCompileAfterOpen(Sender: TObject);
  19. procedure sdvBillsCompileAfterClose(Sender: TObject);
  20. procedure sdvBillsCompileAfterAddRecord(ARecord: TsdDataRecord);
  21. procedure sdvBillsCompileCurrentChanged(ARecord: TsdDataRecord);
  22. private
  23. FProjectData: TObject;
  24. FBillsData: TBillsData;
  25. FBillsCompileTree: TBillsIDTree;
  26. FOnRecChange: TRecChangeEvent;
  27. function GatherChildrenOrg(ANode: TsdIDTreeNode): Double;
  28. procedure UpdateRecordOrg(ABillsID: Integer; ATotalPrice: Double);
  29. function FindChild(AParentNode, ANode: TsdIDTreeNode): TsdIDTreeNode;
  30. function InsertChild(AParentNode, ANode: TsdIDTreeNode): TsdIDTreeNode;
  31. function CompareNodeCode(ANode, ACompareNode: TsdIDTreeNode): Integer;
  32. function GetNextSiblingID(AParent, ANode: TsdIDTreeNode): Integer;
  33. function IsSameNode(ANode, ACompareNode: TsdIDTreeNode): Boolean;
  34. function GetTopParentNode(ANode: TsdIDTreeNode; ALevel: Integer): TsdIDTreeNode;
  35. procedure AddXmjBillsFromLib(AStdBillsNode: TsdIDTreeNode);
  36. function CanAddGclBills: Boolean;
  37. function GetGclBillsParent(AChildNode: TsdIDTreeNode): TsdIDTreeNode;
  38. procedure AddGclBillsFromLib(AStdBillsNode: TsdIDTreeNode);
  39. procedure DoOnAfterDeleteNode(AParent: TsdIDTreeNode);
  40. function GatherChildren(ANode: TsdIDTreeNode; const AFieldName: string): Double;
  41. procedure UpdateParent(ABillsID: Integer; ADifferTotalPrice: Double; const AFieldName: string);
  42. // 经济指标[与其他节点无关]
  43. procedure CalculateDesignPrice(ANode: TBillsIDTreeNode);
  44. // 施工图原设计[增量]
  45. procedure CalculateOrg(ABillsID: Integer);
  46. // 设计错漏增减[增量]
  47. procedure CalculateMis(ABillsID: Integer);
  48. // 其他错漏增减[增量]
  49. procedure CalculateOth(ABillsID: Integer);
  50. procedure CalculateTotal(ABillsID: Integer);
  51. procedure CalculateLeaf(ANode: TBillsIDTreeNode);
  52. procedure GatherNode(ANode: TBillsIDTreeNode);
  53. procedure CalculateBills(ANode: TsdIDTreeNode);
  54. function GetActive: Boolean;
  55. procedure SetOnRecChange(const Value: TRecChangeEvent);
  56. public
  57. constructor Create(AProjectData: TObject);
  58. destructor Destroy; override;
  59. procedure Open;
  60. procedure Close;
  61. procedure ReConnectTree;
  62. procedure AddBillsFromLib(ANode: TsdIDTreeNode; ABillsType: TBillsType);
  63. procedure AddBillsFromDealBills(ARec: TsdDataRecord);
  64. procedure Calculate(ABillsID: Integer);
  65. procedure CalculateAll;
  66. function GetLeafXmjParentID(ABillsID: Integer): Integer;
  67. procedure ExpandNodeTo(ALevel: Integer);
  68. procedure ExpandXmjNode;
  69. procedure ExpandPegXmjNode;
  70. procedure ReorderChildrenCode(ANode: TsdIDTreeNode);
  71. // 所有解锁的节点全部重新锁定
  72. procedure ReLockBaseData;
  73. property ProjectData: TObject read FProjectData;
  74. property BillsData: TBillsData read FBillsData;
  75. property BillsCompileTree: TBillsIDTree read FBillsCompileTree;
  76. property Active: Boolean read GetActive;
  77. property OnRecChange: TRecChangeEvent read FOnRecChange write SetOnRecChange;
  78. end;
  79. implementation
  80. uses
  81. ProjectData, Math, ZhAPI, UtilMethods, ConstUnit, mDataRecord;
  82. {$R *.dfm}
  83. { TBillsCompileData }
  84. constructor TBillsCompileData.Create(AProjectData: TObject);
  85. begin
  86. inherited Create(nil);
  87. FProjectData := AProjectData;
  88. FBillsData := TProjectData(FProjectData).BillsData;
  89. FBillsCompileTree := TBillsIDTree.Create;
  90. FBillsCompileTree.KeyFieldName := 'ID';
  91. FBillsCompileTree.ParentFieldName := 'ParentID';
  92. FBillsCompileTree.NextSiblingFieldName := 'NextSiblingID';
  93. FBillsCompileTree.AutoCreateKeyID := True;
  94. FBillsCompileTree.AutoExpand := True;
  95. FBillsCompileTree.DataView := sdvBillsCompile;
  96. FBillsCompileTree.SeedID := Max(FBillsCompileTree.SeedID, 100);
  97. FBillsCompileTree.DoOnAfterDeleteNode := DoOnAfterDeleteNode;
  98. FBillsCompileTree.OnReCalcParent := Calculate;
  99. end;
  100. destructor TBillsCompileData.Destroy;
  101. begin
  102. FBillsCompileTree.Free;
  103. inherited;
  104. end;
  105. procedure TBillsCompileData.Open;
  106. begin
  107. sdvBillsCompile.DataSet := TProjectData(FProjectData).BillsData.sddBills;
  108. sdvBillsCompile.Open;
  109. FBillsCompileTree.SeedID := Max(FBillsCompileTree.SeedID, 100);
  110. end;
  111. procedure TBillsCompileData.ReConnectTree;
  112. begin
  113. FBillsCompileTree.DataView := nil;
  114. FBillsCompileTree.DataView := sdvBillsCompile;
  115. end;
  116. procedure TBillsCompileData.sdvBillsCompileGetText(var Text: String;
  117. ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
  118. DisplayText: Boolean);
  119. procedure GetEditText;
  120. var
  121. sFormula: string;
  122. begin
  123. if SameText('OrgQuantity', AColumn.FieldName) then
  124. sFormula := ARecord.ValueByName('OrgFormula').AsString
  125. else if SameText('MisQuantity', AColumn.FieldName) then
  126. sFormula := ARecord.ValueByName('MisFormula').AsString
  127. else if SameText('OthQuantity', AColumn.FieldName) then
  128. sFormula := ARecord.ValueByName('OthFormula').AsString
  129. else
  130. sFormula := '';
  131. if sFormula <> '' then
  132. Text := sFormula;
  133. end;
  134. procedure GetDisplayText;
  135. begin
  136. if (Pos('Price', AColumn.FieldName) > 0) or
  137. (Pos('Quantity', AColumn.FieldName) > 0) then
  138. begin
  139. if Assigned(AValue) and (AValue.AsFloat = 0) then
  140. Text := '';
  141. end;
  142. end;
  143. begin
  144. if DisplayText then
  145. GetDisplayText
  146. else
  147. GetEditText;
  148. end;
  149. procedure TBillsCompileData.ExpandNodeTo(ALevel: Integer);
  150. begin
  151. BillsCompileTree.ExpandLevel := ALevel;
  152. end;
  153. procedure TBillsCompileData.ExpandXmjNode;
  154. var
  155. iIndex: Integer;
  156. stnNode: TsdIDTreeNode;
  157. begin
  158. for iIndex := 0 to BillsCompileTree.Count - 1 do
  159. begin
  160. stnNode := BillsCompileTree.Items[iIndex];
  161. if (stnNode.ParentID <> -1) then
  162. stnNode.Parent.Expanded := stnNode.Rec.ValueByName('B_Code').AsString = '';
  163. end;
  164. end;
  165. procedure TBillsCompileData.sdvBillsCompileAfterValueChanged(
  166. AValue: TsdValue);
  167. procedure ResetChildrenLockedInfo(ANode: TsdIDTreeNode; ALockedInfo: Boolean);
  168. var
  169. iChild: Integer;
  170. begin
  171. if not Assigned(ANode) then Exit;
  172. if ANode.Rec.ValueByName('LockedLevel').AsBoolean then
  173. ANode.Rec.ValueByName('LockedInfo').AsBoolean := ALockedInfo;
  174. if ANode.HasChildren then
  175. for iChild := 0 to ANode.ChildCount - 1 do
  176. ResetChildrenLockedInfo(ANode.ChildNodes[iChild], ALockedInfo);
  177. end;
  178. var
  179. stnNode: TsdIDTreeNode;
  180. begin
  181. if SameText(AValue.FieldName, 'OrgQuantity') or
  182. SameText(AValue.FieldName, 'OrgTotalPrice') then
  183. CalculateOrg(AValue.Owner.ValueByName('ID').AsInteger)
  184. else if SameText(AValue.FieldName, 'MisQuantity') or
  185. SameText(AValue.FieldName, 'MisTotalPrice') then
  186. CalculateMis(AValue.Owner.ValueByName('ID').AsInteger)
  187. else if SameText(AValue.FieldName, 'OthQuantity') or
  188. SameText(AValue.FieldName, 'OthTotalPrice') then
  189. CalculateOth(AValue.Owner.ValueByName('ID').AsInteger)
  190. else if SameText(AValue.FieldName, 'Price') or
  191. SameText(AValue.FieldName, 'DgnQuantity1') then
  192. CalculateTotal(AValue.Owner.ValueByName('ID').AsInteger);
  193. if (AValue.FieldName = 'LockedInfo') then
  194. begin
  195. stnNode := BillsCompileTree.FindNode(AValue.Owner.ValueByName('ID').AsInteger);
  196. ResetChildrenLockedInfo(stnNode, AValue.AsBoolean);
  197. end;
  198. end;
  199. function TBillsCompileData.GatherChildrenOrg(ANode: TsdIDTreeNode): Double;
  200. var
  201. iChild: Integer;
  202. begin
  203. if ANode = nil then Exit;
  204. if ANode.HasChildren and Assigned(ANode.FirstChild) then
  205. begin
  206. Result := 0;
  207. for iChild := 0 to ANode.ChildCount - 1 do
  208. Result := Result + GatherChildrenOrg(ANode.ChildNodes[iChild]);
  209. Result := TotalPriceRoundTo(Result);
  210. end
  211. else
  212. if Assigned(ANode.Rec) and Assigned(ANode.Rec.ValueByName('TotalPrice')) then
  213. Result := ANode.Rec.ValueByName('TotalPrice').AsFloat
  214. else
  215. Result := 0;
  216. end;
  217. procedure TBillsCompileData.UpdateRecordOrg(ABillsID: Integer;
  218. ATotalPrice: Double);
  219. var
  220. stnNode: TsdIDTreeNode;
  221. begin
  222. stnNode := BillsCompileTree.FindNode(ABillsID);
  223. if not Assigned(stnNode) then Exit;
  224. with stnNode.Rec do
  225. begin
  226. ValueByName('TotalPrice').AsFloat := TotalPriceRoundTo(
  227. ValueByName('TotalPrice').AsFloat + ATotalPrice);
  228. if ValueByName('DgnQuantity1').AsFloat <> 0 then
  229. ValueByName('DgnPrice').AsFloat := PriceRoundTo(
  230. ValueByName('TotalPrice').AsFloat/ValueByName('DgnQuantity1').AsFloat);
  231. end;
  232. UpdateRecordOrg(stnNode.ParentID, ATotalPrice);
  233. end;
  234. procedure TBillsCompileData.sdvBillsCompileBeforeValueChange(
  235. AValue: TsdValue; const NewValue: Variant; var Allow: Boolean);
  236. begin
  237. // 清单编号和项目节编号不可同时存在
  238. if SameText(AValue.FieldName, 'Code') then
  239. begin
  240. if AValue.Owner.ValueByName('B_Code').AsString <> '' then
  241. DataSetErrorMessage(Allow, '已存在清单编号,不可输入项目节编号!');
  242. end
  243. else if SameText(AValue.FieldName, 'B_Code') then
  244. begin
  245. if AValue.Owner.ValueByName('Code').AsString <> '' then
  246. DataSetErrorMessage(Allow, '已存在项目节编号,不可输入清单编号!');
  247. end
  248. //
  249. else if SameText(AValue.FieldName, 'Price') then
  250. begin
  251. if AValue.Owner.ValueByName('AddGatherTotalPrice').AsFloat <> 0 then
  252. DataSetErrorMessage(Allow, '该清单已经开始计量,不可修改单价!');
  253. end
  254. // 变更清单不可修改0号台账数据
  255. else if SameText(AValue.FieldName, 'OrgQuantity') or
  256. SameText(AValue.FieldName, 'MisQuantity') or
  257. SameText(AValue.FieldName, 'OthQuantity') then
  258. begin
  259. if AValue.Owner.ValueByName('IsMeasureAdd').AsBoolean then
  260. DataSetErrorMessage(Allow, '变更清单不可填写0号台账数量与金额');
  261. end;
  262. if not Allow then Exit;
  263. if SameText(AValue.FieldName, 'OrgQuantity') or
  264. SameText(AValue.FieldName, 'MisQuantity') or
  265. SameText(AValue.FieldName, 'OthQuantity') or
  266. SameText(AValue.FieldName, 'OrgTotalPrice') or
  267. SameText(AValue.FieldName, 'MisTotalPrice') or
  268. SameText(AValue.FieldName, 'OthTotalPrice') or
  269. SameText(AValue.FieldName, 'Price') then
  270. begin
  271. TBillsRecord(AValue.Owner).CacheOrgTP := AValue.Owner.ValueByName('OrgTotalPrice').AsFloat;
  272. TBillsRecord(AValue.Owner).CacheMisTP := AValue.Owner.ValueByName('MisTotalPrice').AsFloat;
  273. TBillsRecord(AValue.Owner).CacheOthTP := AValue.Owner.ValueByName('OthTotalPrice').AsFloat;
  274. end;
  275. end;
  276. procedure TBillsCompileData.CalculateAll;
  277. procedure RecursiveCalc(ANode: TsdIDTreeNode);
  278. begin
  279. if not Assigned(ANode) then Exit;
  280. if ANode.HasChildren then
  281. begin
  282. RecursiveCalc(ANode.FirstChild);
  283. GatherNode(TBillsIDTreeNode(ANode));
  284. end
  285. else
  286. CalculateLeaf(TBillsIDTreeNode(ANode));
  287. RecursiveCalc(ANode.NextSibling);
  288. end;
  289. procedure BeginCalc;
  290. begin
  291. sdvBillsCompile.BeforeValueChange := nil;
  292. sdvBillsCompile.AfterValueChanged := nil;
  293. end;
  294. procedure EndCalc;
  295. begin
  296. sdvBillsCompile.BeforeValueChange := sdvBillsCompileBeforeValueChange;
  297. sdvBillsCompile.AfterValueChanged := sdvBillsCompileAfterValueChanged;
  298. end;
  299. begin
  300. BeginCalc;
  301. try
  302. RecursiveCalc(BillsCompileTree.FirstNode);
  303. finally
  304. EndCalc;
  305. end;
  306. end;
  307. procedure TBillsCompileData.AddBillsFromLib(ANode: TsdIDTreeNode;
  308. ABillsType: TBillsType);
  309. begin
  310. if not Assigned(ANode) then Exit;
  311. if ABillsType = btXm then
  312. AddXmjBillsFromLib(ANode)
  313. else if ABillsType = btGcl then
  314. AddGclBillsFromLib(ANode);
  315. end;
  316. procedure TBillsCompileData.AddGclBillsFromLib(
  317. AStdBillsNode: TsdIDTreeNode);
  318. var
  319. stnParent, stnStdNode: TsdIDTreeNode;
  320. iLevel: Integer;
  321. begin
  322. if not CanAddGclBills then
  323. raise Exception.Create('当前节点下不可添加工程量清单!');
  324. stnParent := GetGclBillsParent(BillsCompileTree.Selected);
  325. if TBillsIDTreeNode(stnParent).HasLedger or
  326. (not stnParent.HasChildren and TBillsIDTreeNode(stnParent).HasMeasure) then
  327. raise Exception.Create('当前节点不可添加工程量清单!');
  328. stnStdNode := GetTopParentNode(AStdBillsNode, AStdBillsNode.Level);
  329. for iLevel := 1 to AStdBillsNode.Level + 1 do
  330. begin
  331. if stnStdNode.Rec.ValueByName('B_Code').AsString <> '' then
  332. if FindChild(stnParent, stnStdNode) <> nil then
  333. stnParent := FindChild(stnParent, stnStdNode)
  334. else
  335. stnParent := InsertChild(stnParent, stnStdNode);
  336. stnStdNode := GetTopParentNode(AStdBillsNode, AStdBillsNode.Level - iLevel);
  337. end;
  338. end;
  339. procedure TBillsCompileData.AddXmjBillsFromLib(
  340. AStdBillsNode: TsdIDTreeNode);
  341. var
  342. stnStdNode, stnCurNode: TsdIDTreeNode;
  343. iLevel: Integer;
  344. begin
  345. stnStdNode := GetTopParentNode(AStdBillsNode, AStdBillsNode.Level);
  346. stnCurNode := nil;
  347. for iLevel := 1 to AStdBillsNode.Level + 1 do
  348. begin
  349. if FindChild(stnCurNode, stnStdNode) <> nil then
  350. stnCurNode := FindChild(stnCurNode, stnStdNode)
  351. else
  352. begin
  353. if TBillsIDTreeNode(stnCurNode).HasLedger or
  354. (not stnCurNode.HasChildren and TBillsIDTreeNode(stnCurNode).HasMeasure) then
  355. raise Exception.Create('不可添加该项目节数据!')
  356. else
  357. stnCurNode := InsertChild(stnCurNode, stnStdNode);
  358. end;
  359. stnStdNode := GetTopParentNode(AStdBillsNode, AStdBillsNode.Level - iLevel);
  360. end;
  361. end;
  362. function TBillsCompileData.CanAddGclBills: Boolean;
  363. function CheckChildrenHasXmj(ANode: TsdIDTreeNode): Boolean;
  364. var
  365. stnCurNode: TsdIDTreeNode;
  366. begin
  367. Result := False;
  368. if not ANode.HasChildren then Exit;
  369. stnCurNode := ANode.FirstChild;
  370. while not Result and Assigned(stnCurNode) do
  371. begin
  372. Result := Result or (stnCurNode.Rec.ValueByName('Code').AsString <> '');
  373. if stnCurNode.HasChildren then
  374. Result := Result or CheckChildrenHasXmj(stnCurNode);
  375. stnCurNode := stnCurNode.NextSibling;
  376. end;
  377. end;
  378. function CheckParentIsXmj(ANode: TsdIDTreeNode): Boolean;
  379. begin
  380. Result := False;
  381. if not Assigned(ANode) then Exit;
  382. Result := ANode.Rec.ValueByName('Code').AsString <> '';
  383. if not Result then
  384. Result := Result or CheckParentIsXmj(ANode.Parent);
  385. end;
  386. begin
  387. Result := False;
  388. if not Assigned(BillsCompileTree.Selected) then Exit;
  389. Result := CheckParentIsXmj(BillsCompileTree.Selected)
  390. and not CheckChildrenHasXmj(BillsCompileTree.Selected);
  391. end;
  392. function TBillsCompileData.CompareNodeCode(ANode,
  393. ACompareNode: TsdIDTreeNode): Integer;
  394. begin
  395. if ANode.Rec.ValueByName('Code').AsString <> '' then
  396. Result := CompareCode(ANode.Rec.ValueByName('Code').AsString,
  397. ACompareNode.Rec.ValueByName('Code').AsString)
  398. else if ANode.Rec.ValueByName('B_Code').AsString <> '' then
  399. Result := CompareCode(ANode.Rec.ValueByName('B_Code').AsString,
  400. ACompareNode.Rec.ValueByName('B_Code').AsString);
  401. end;
  402. function TBillsCompileData.GetGclBillsParent(
  403. AChildNode: TsdIDTreeNode): TsdIDTreeNode;
  404. begin
  405. if AChildNode.Rec.ValueByName('B_Code').AsString <> '' then
  406. Result := GetGclBillsParent(AChildNode.Parent)
  407. else
  408. Result := AChildNode;
  409. end;
  410. function TBillsCompileData.GetNextSiblingID(AParent,
  411. ANode: TsdIDTreeNode): Integer;
  412. var
  413. stnCurNode: TsdIDTreeNode;
  414. begin
  415. Result := -1;
  416. if Assigned(AParent) then
  417. stnCurNode := AParent.FirstChild
  418. else
  419. stnCurNode := BillsCompileTree.FirstNode;
  420. if not Assigned(stnCurNode) then Exit;
  421. while Assigned(stnCurNode) do
  422. begin
  423. if CompareNodeCode(stnCurNode, ANode) >= 0 then
  424. begin
  425. Result := stnCurNode.ID;
  426. Exit;
  427. end;
  428. stnCurNode := stnCurNode.NextSibling;
  429. end;
  430. end;
  431. function TBillsCompileData.GetTopParentNode(ANode: TsdIDTreeNode;
  432. ALevel: Integer): TsdIDTreeNode;
  433. begin
  434. Result := ANode;
  435. while Assigned(Result.Parent) and (Result.Level + ALevel > ANode.Level) do
  436. Result := Result.Parent;
  437. end;
  438. function TBillsCompileData.IsSameNode(ANode,
  439. ACompareNode: TsdIDTreeNode): Boolean;
  440. begin
  441. Result := (ANode.Rec.ValueByName('Code').AsString = ACompareNode.Rec.ValueByName('Code').AsString)
  442. and (ANode.Rec.ValueByName('B_Code').AsString = ACompareNode.Rec.ValueByName('B_Code').AsString)
  443. and (ANode.Rec.ValueByName('Name').AsString = ACompareNode.Rec.ValueByName('Name').AsString);
  444. end;
  445. function TBillsCompileData.FindChild(AParentNode,
  446. ANode: TsdIDTreeNode): TsdIDTreeNode;
  447. function FindSibling(AFirstNode, ANode: TsdIDTreeNode): TsdIDTreeNode;
  448. var
  449. stnCurNode: TsdIDTreeNode;
  450. begin
  451. Result := nil;
  452. stnCurNode := AFirstNode;
  453. while Assigned(stnCurNode) and not Assigned(Result) do
  454. begin
  455. if IsSameNode(ANode, stnCurNode) then
  456. Result := stnCurNode;
  457. stnCurNode := stnCurNode.NextSibling;
  458. end;
  459. end;
  460. begin
  461. if not Assigned(AParentNode) then
  462. Result := FindSibling(BillsCompileTree.FirstNode, ANode)
  463. else
  464. Result := FindSibling(AParentNode.FirstChild, ANode);
  465. end;
  466. function TBillsCompileData.InsertChild(AParentNode,
  467. ANode: TsdIDTreeNode): TsdIDTreeNode;
  468. var
  469. iNextSiblingID: Integer;
  470. begin
  471. iNextSiblingID := GetNextSiblingID(AParentNode, ANode);
  472. if Assigned(AParentNode) then
  473. Result := BillsCompileTree.Add(AParentNode.ID, iNextSiblingID)
  474. else
  475. Result := BillsCompileTree.Add(-1, iNextSiblingID);
  476. Result.Rec.ValueByName('Code').AsString := ANode.Rec.ValueByName('Code').AsString;
  477. Result.Rec.ValueByName('B_Code').AsString := ANode.Rec.ValueByName('B_Code').AsString;
  478. Result.Rec.ValueByName('Name').AsString := ANode.Rec.ValueByName('Name').AsString;
  479. Result.Rec.ValueByName('Units').AsString := ANode.Rec.ValueByName('Unit').AsString;
  480. end;
  481. procedure TBillsCompileData.sdvBillsCompileSetText(var Text: String;
  482. ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
  483. var Allow: Boolean);
  484. procedure SetTextErrorHint(const AHint: string);
  485. begin
  486. ErrorMessage(AHint);
  487. Allow := False;
  488. end;
  489. procedure SetQuantity(const APre: string);
  490. begin
  491. // 0号台账改为三项合计后,不记录输入的公式,但允许公式计算
  492. if CheckStringNull(Text) or CheckNumeric(Text) then
  493. Text := FloatToStr(QuantityRoundTo(StrToFloatDef(Text, 0)))
  494. else
  495. begin
  496. ARecord.ValueByName(APre + 'Formula').AsString := Text;
  497. Text := FloatToStr(QuantityRoundTo(EvaluateExprs(Text)));
  498. end;
  499. ARecord.ValueByName('CalcType').AsInteger := 0;
  500. end;
  501. procedure SetTotalPrice;
  502. begin
  503. Text := FloatToStr(TotalPriceRoundTo(StrToFloatDef(Text, 0)));
  504. ARecord.ValueByName('CalcType').AsInteger := 1;
  505. end;
  506. procedure SetDgnQuantity;
  507. begin
  508. Text := FloatToStr(QuantityRoundTo(StrToFloatDef(Text, 0)));
  509. end;
  510. procedure SetPrice;
  511. begin
  512. Text := FloatToStr(PriceRoundTo(StrToFloatDef(Text, 0)));
  513. end;
  514. procedure DoCurChanged;
  515. begin
  516. if SameText(AColumn.FieldName, 'OrgQuantity') then
  517. SetQuantity('Org')
  518. else if SameText(AColumn.FieldName, 'MisQuantity') then
  519. SetQuantity('Mis')
  520. else if SameText(AColumn.FieldName, 'OthQuantity') then
  521. SetQuantity('Oth')
  522. else if SameText(AColumn.FieldName, 'OrgTotalPrice') or
  523. SameText(AColumn.FieldName, 'MisTotalPrice') or
  524. SameText(AColumn.FieldName, 'OthTotalPrice') then
  525. SetTotalPrice
  526. else if Pos('DgnQuantity', AColumn.FieldName) = 1 then
  527. SetDgnQuantity
  528. else if SameText(AColumn.FieldName, 'Price') then
  529. SetPrice;
  530. end;
  531. procedure CheckLockedData;
  532. begin
  533. if SameText(AColumn.FieldName, 'Code') or
  534. SameText(AColumn.FieldName, 'B_Code') or
  535. SameText(AColumn.FieldName, 'Name') or
  536. SameText(AColumn.FieldName, 'Units') or
  537. SameText(AColumn.FieldName, 'Price') or
  538. SameText(AColumn.FieldName, 'OrgQuantity') or
  539. SameText(AColumn.FieldName, 'OrgTotalPrice') or
  540. SameText(AColumn.FieldName, 'MisQuantity') or
  541. SameText(AColumn.FieldName, 'MisTotalPrice') or
  542. SameText(AColumn.FieldName, 'OthQuantity') or
  543. SameText(AColumn.FieldName, 'OthTotalPrice') or
  544. SameText(AColumn.FieldName, 'DrawingCode')then
  545. if ARecord.ValueByName('LockedInfo').AsBoolean then
  546. SetTextErrorHint('清单信息已被锁定,不允许修改编号、名称、单位、清单单价、0号台账数量与金额、图号!');
  547. end;
  548. procedure CheckNodeWritable;
  549. var
  550. vNode: TBillsIDTreeNode;
  551. iCreatePhase: Integer;
  552. begin
  553. if not Allow then Exit;
  554. vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(ARecord.ValueByName('ID').AsInteger));
  555. iCreatePhase := vNode.Rec.ValueByName('CreatePhaseID').AsInteger;
  556. if vNode.HasChildren then
  557. begin
  558. if Text = '' then
  559. Exit
  560. else if ((Pos('Quantity', AColumn.FieldName) > 0) and (Pos('Dgn', AColumn.FieldName) <=0)) or
  561. (Pos('TotalPrice', AColumn.FieldName) > 0) then
  562. SetTextErrorHint('该清单有子计算项,不能直接修改!')
  563. else if (Pos('Price', AColumn.FieldName) > 0) then
  564. SetTextErrorHint('仅最底层清单可输入单价!');
  565. if not Allow then Exit;
  566. end
  567. else
  568. begin
  569. if SameText('OrgTotalPrice', AColumn.FieldName) or
  570. SameText('MisTotalPrice', AColumn.FieldName) or
  571. SameText('OthTotalPrice', AColumn.FieldName) then
  572. begin
  573. if not vNode.TotalPriceEnable then
  574. SetTextErrorHint('该清单不可直接输入金额,如需直接输入金额,请先清空所有数量、单价!');
  575. end;
  576. if not Allow then Exit;
  577. if SameText('Price', AColumn.FieldName) or
  578. SameText('OrgQuantity', AColumn.FieldName) or
  579. SameText('MisQuantity', AColumn.FieldName) or
  580. SameText('OthQuantity', AColumn.FieldName) then
  581. begin
  582. if not vNode.CountPriceEnable then
  583. SetTextErrorHint('该清单不可输入数量单价,如需使用数量×单价计算,请先清空所有直接输入的金额!');
  584. end;
  585. if not Allow then Exit;
  586. end;
  587. if SameText('Code', AColumn.FieldName) or
  588. SameText('B_Code', AColumn.FieldName) or
  589. SameText('Name', AColumn.FieldName) or
  590. SameText('Units', AColumn.FieldName) or
  591. SameText('Price', AColumn.FieldName) then
  592. if TBillsIDTreeNode(vNode).HasMeasure then
  593. SetTextErrorHint('该清单已经计量,不可修改清单编号');
  594. end;
  595. begin
  596. if not Assigned(AValue) then Exit;
  597. // 修改后数据与原数据相同则不提交
  598. if (AValue.AsString = Text) or ((AValue.AsFloat = 0) and (Text = '')) then Exit;
  599. CheckLockedData;
  600. if not Allow then Exit;
  601. CheckNodeWritable;
  602. if not Allow then Exit;
  603. Text := Trim(Text);
  604. if Pos('=', Text) = 1 then
  605. Text := Copy(Text, 2, Length(Text) - 1);
  606. DoCurChanged;
  607. end;
  608. function TBillsCompileData.GetActive: Boolean;
  609. begin
  610. Result := sdvBillsCompile.Active;
  611. end;
  612. function TBillsCompileData.GetLeafXmjParentID(ABillsID: Integer): Integer;
  613. var
  614. stnNode: TsdIDTreeNode;
  615. begin
  616. stnNode := BillsCompileTree.FindNode(ABillsID);
  617. Result := GetGclBillsParent(stnNode).ID;
  618. end;
  619. procedure TBillsCompileData.sdvBillsCompileAfterOpen(Sender: TObject);
  620. begin
  621. BillsCompileTree.Active := True;
  622. end;
  623. procedure TBillsCompileData.sdvBillsCompileAfterClose(Sender: TObject);
  624. begin
  625. BillsCompileTree.Active := False;
  626. end;
  627. procedure TBillsCompileData.ReorderChildrenCode(ANode: TsdIDTreeNode);
  628. var
  629. iChild: Integer;
  630. sParentCode: string;
  631. stnChild: TsdIDTreeNode;
  632. begin
  633. if not Assigned(ANode) then Exit;
  634. sParentCode := ANode.Rec.ValueByName('Code').AsString;
  635. for iChild := 0 to ANode.ChildCount - 1 do
  636. begin
  637. stnChild := ANode.ChildNodes[iChild];
  638. if stnChild.Rec.ValueByName('Code').AsString <> '' then
  639. stnChild.Rec.ValueByName('Code').AsString := sParentCode + '-' + IntToStr(iChild + 1);
  640. ReorderChildrenCode(stnChild);
  641. end;
  642. end;
  643. procedure TBillsCompileData.sdvBillsCompileAfterAddRecord(
  644. ARecord: TsdDataRecord);
  645. begin
  646. // 解锁前,新增清单为变更清单,解锁后,新增清单为0号台账清单
  647. if TProjectData(FProjectData).ProjProperties.PhaseCount > 0 then
  648. ARecord.ValueByName('IsMeasureAdd').AsBoolean := not TProjectData(FProjectData).CanUnlockInfo;
  649. end;
  650. procedure TBillsCompileData.DoOnAfterDeleteNode(AParent: TsdIDTreeNode);
  651. begin
  652. if Assigned(AParent) and (AParent.ID > 0) then
  653. Calculate(AParent.ID);
  654. end;
  655. procedure TBillsCompileData.Close;
  656. begin
  657. sdvBillsCompile.Close;
  658. end;
  659. procedure TBillsCompileData.SetOnRecChange(const Value: TRecChangeEvent);
  660. begin
  661. FOnRecChange := Value;
  662. end;
  663. procedure TBillsCompileData.sdvBillsCompileCurrentChanged(
  664. ARecord: TsdDataRecord);
  665. begin
  666. if Assigned(FOnRecChange) then
  667. FOnRecChange(ARecord);
  668. end;
  669. procedure TBillsCompileData.ReLockBaseData;
  670. procedure LockNodeBaseData(ANode: TsdIDTreeNode);
  671. begin
  672. if not Assigned(ANode) then Exit;
  673. if ANode.Rec.ValueByName('LockedLevel').AsBoolean then
  674. if not ANode.Rec.ValueByName('LockedInfo').AsBoolean then
  675. ANode.Rec.ValueByName('LockedInfo').AsBoolean := True;
  676. LockNodeBaseData(ANode.FirstChild);
  677. LockNodeBaseData(ANode.NextSibling);
  678. end;
  679. begin
  680. sdvBillsCompile.AfterValueChanged := nil;
  681. try
  682. LockNodeBaseData(FBillsCompileTree.FirstNode);
  683. finally
  684. sdvBillsCompile.AfterValueChanged := sdvBillsCompileAfterValueChanged;
  685. end;
  686. end;
  687. procedure TBillsCompileData.AddBillsFromDealBills(ARec: TsdDataRecord);
  688. var
  689. stnParent, stnNode: TsdIDTreeNode;
  690. begin
  691. if not CanAddGclBills then
  692. raise Exception.Create('当前节点下不可添加工程量清单!');
  693. stnParent := GetGclBillsParent(BillsCompileTree.Selected);
  694. if TBillsIDTreeNode(stnParent).HasLedger or
  695. (not stnParent.HasChildren and TBillsIDTreeNode(stnParent).HasMeasure) then
  696. raise Exception.Create('当前节点不可添加工程量清单!');
  697. stnNode := BillsCompileTree.Add(stnParent.ID, -1);
  698. stnNode.Rec.ValueByName('B_Code').AsString := ARec.ValueByName('B_Code').AsString;
  699. stnNode.Rec.ValueByName('Name').AsString := ARec.ValueByName('Name').AsString;
  700. stnNode.Rec.ValueByName('Units').AsString := ARec.ValueByName('Units').AsString;
  701. stnNode.Rec.ValueByName('Price').AsString := ARec.ValueByName('Price').AsString;
  702. end;
  703. procedure TBillsCompileData.CalculateMis(ABillsID: Integer);
  704. var
  705. vNode: TBillsIDTreeNode;
  706. iChild: Integer;
  707. begin
  708. vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(ABillsID));
  709. if not Assigned(vNode) then Exit;
  710. if vNode.HasChildren then
  711. begin
  712. for iChild := 0 to vNode.ChildCount - 1 do
  713. CalculateMis(vNode.ChildNodes[iChild].ID);
  714. end
  715. else
  716. begin
  717. with vNode.Rec do
  718. begin
  719. // 数量单价模式则计算金额
  720. if CalcType.AsInteger = 0 then
  721. MisTotalPrice.AsFloat := TotalPriceRoundTo(MisQuantity.AsFloat * Price.AsFloat);
  722. // 金额与修改前不一样,则向父项增量
  723. if MisTotalPrice.AsFloat <> CacheMisTP then
  724. begin
  725. UpdateParent(vNode.ParentID, MisTotalPrice.AsFloat - CacheMisTP, 'MisTotalPrice');
  726. Quantity.AsFloat := QuantityRoundTo(
  727. OrgQuantity.AsFloat + MisQuantity.AsFloat + OthQuantity.AsFloat);
  728. TotalPrice.AsFloat := TotalPriceRoundTo(
  729. OrgTotalPrice.AsFloat + MisTotalPrice.AsFloat + OthTotalPrice.AsFloat);
  730. end;
  731. end;
  732. end;
  733. CalculateDesignPrice(vNode);
  734. end;
  735. procedure TBillsCompileData.CalculateOrg(ABillsID: Integer);
  736. var
  737. vNode: TBillsIDTreeNode;
  738. iChild: Integer;
  739. begin
  740. vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(ABillsID));
  741. if not Assigned(vNode) then Exit;
  742. if vNode.HasChildren then
  743. begin
  744. for iChild := 0 to vNode.ChildCount - 1 do
  745. CalculateOrg(vNode.ChildNodes[iChild].ID);
  746. end
  747. else
  748. begin
  749. with vNode.Rec do
  750. begin
  751. // 数量单价模式则计算金额
  752. if CalcType.AsInteger = 0 then
  753. OrgTotalPrice.AsFloat := TotalPriceRoundTo(OrgQuantity.AsFloat * Price.AsFloat);
  754. // 金额与修改前不一样,则向父项增量
  755. if CacheOrgTP <> OrgTotalPrice.AsFloat then
  756. begin
  757. UpdateParent(vNode.ParentID, OrgTotalPrice.AsFloat - CacheOrgTP, 'OrgTotalPrice');
  758. Quantity.AsFloat := QuantityRoundTo(
  759. OrgQuantity.AsFloat + MisQuantity.AsFloat + OthQuantity.AsFloat);
  760. TotalPrice.AsFloat := TotalPriceRoundTo(
  761. OrgTotalPrice.AsFloat + MisTotalPrice.AsFloat + OthTotalPrice.AsFloat);
  762. end;
  763. end;
  764. end;
  765. CalculateDesignPrice(vNode);
  766. end;
  767. procedure TBillsCompileData.CalculateOth(ABillsID: Integer);
  768. var
  769. vNode: TBillsIDTreeNode;
  770. iChild: Integer;
  771. begin
  772. vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(ABillsID));
  773. if not Assigned(vNode) then Exit;
  774. if vNode.HasChildren then
  775. begin
  776. for iChild := 0 to vNode.ChildCount - 1 do
  777. CalculateOth(vNode.ChildNodes[iChild].ID);
  778. end
  779. else
  780. begin
  781. with vNode.Rec do
  782. begin
  783. // 数量单价模式则计算金额
  784. if CalcType.AsInteger = 0 then
  785. OthTotalPrice.AsFloat := TotalPriceRoundTo(OthQuantity.AsFloat * Price.AsFloat);
  786. // 金额与修改前不一样,则向父项增量
  787. if OthTotalPrice.AsFloat <> CacheOthTP then
  788. begin
  789. UpdateParent(vNode.ParentID, OthTotalPrice.AsFloat - CacheOthTP, 'OthTotalPrice');
  790. Quantity.AsFloat := QuantityRoundTo(
  791. OrgQuantity.AsFloat + MisQuantity.AsFloat + OthQuantity.AsFloat);
  792. TotalPrice.AsFloat := TotalPriceRoundTo(
  793. OrgTotalPrice.AsFloat + MisTotalPrice.AsFloat+ OthTotalPrice.AsFloat);
  794. end;
  795. end;
  796. end;
  797. CalculateDesignPrice(vNode);
  798. end;
  799. function TBillsCompileData.GatherChildren(ANode: TsdIDTreeNode;
  800. const AFieldName: string): Double;
  801. var
  802. iChild: Integer;
  803. begin
  804. Result := 0;
  805. if not Assigned(ANode) then Exit;
  806. if ANode.HasChildren and Assigned(ANode.FirstChild) then
  807. begin
  808. Result := 0;
  809. for iChild := 0 to ANode.ChildCount - 1 do
  810. Result := Result + ANode.Rec.ValueByName(AFieldName).AsFloat;
  811. Result := TotalPriceRoundTo(Result);
  812. end
  813. else
  814. if Assigned(ANode.Rec) and Assigned(ANode.Rec.ValueByName(AFieldName)) then
  815. Result := ANode.Rec.ValueByName(AFieldName).AsFloat;
  816. end;
  817. procedure TBillsCompileData.UpdateParent(ABillsID: Integer;
  818. ADifferTotalPrice: Double; const AFieldName: string);
  819. var
  820. vNode: TBillsIDTreeNode;
  821. begin
  822. vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(ABillsID));
  823. if not Assigned(vNode) then Exit;
  824. with vNode.Rec do
  825. begin
  826. ValueByName(AFieldName).AsFloat := TotalPriceRoundTo(
  827. ValueByName(AFieldName).AsFloat + ADifferTotalPrice);
  828. TotalPrice.AsFloat := TotalPriceRoundTo(TotalPrice.AsFloat + ADifferTotalPrice);
  829. end;
  830. CalculateDesignPrice(vNode);
  831. UpdateParent(vNode.ParentID, ADifferTotalPrice, AFieldName);
  832. end;
  833. procedure TBillsCompileData.CalculateTotal(ABillsID: Integer);
  834. begin
  835. CalculateOrg(ABillsID);
  836. CalculateMis(ABillsID);
  837. CalculateOth(ABillsID);
  838. end;
  839. procedure TBillsCompileData.CalculateBills(ANode: TsdIDTreeNode);
  840. var
  841. iChild: Integer;
  842. begin
  843. if not Assigned(ANode) then Exit;
  844. if ANode.HasChildren then
  845. begin
  846. for iChild := 0 to ANode.ChildCount - 1 do
  847. CalculateBills(ANode.ChildNodes[iChild]);
  848. GatherNode(TBillsIDTreeNode(ANode));
  849. end
  850. else
  851. CalculateLeaf(TBillsIDTreeNode(ANode));
  852. end;
  853. procedure TBillsCompileData.CalculateLeaf(ANode: TBillsIDTreeNode);
  854. begin
  855. if not Assigned(ANode) or ANode.HasChildren then Exit;
  856. with ANode.Rec do
  857. begin
  858. // 分项
  859. if CalcType.AsFloat = 0 then
  860. begin
  861. OrgTotalPrice.AsFloat := TotalPriceRoundTo(Price.AsFloat * OrgQuantity.AsFloat);
  862. MisTotalPrice.AsFloat := TotalPriceRoundTo(Price.AsFloat * MisQuantity.AsFloat);
  863. OthTotalPrice.AsFloat := TotalPriceRoundTo(Price.AsFloat * OthQuantity.AsFloat);
  864. end;
  865. // 汇总
  866. Quantity.AsFloat := QuantityRoundTo(
  867. OrgQuantity.AsFloat + MisQuantity.AsFloat + OthQuantity.AsFloat);
  868. TotalPrice.AsFloat := TotalPriceRoundTo(
  869. OrgTotalPrice.AsFloat + MisTotalPrice.AsFloat + OthTotalPrice.AsFloat);
  870. end;
  871. CalculateDesignPrice(ANode);
  872. end;
  873. procedure TBillsCompileData.GatherNode(ANode: TBillsIDTreeNode);
  874. var
  875. iChild: Integer;
  876. fOrg, fMis, fOth: Double;
  877. vChild: TBillsIDTreeNode;
  878. begin
  879. fOrg := 0;
  880. fMis := 0;
  881. fOth := 0;
  882. for iChild := 0 to ANode.ChildCount - 1 do
  883. begin
  884. vChild := TBillsIDTreeNode(ANode.ChildNodes[iChild]);
  885. fOrg := fOrg + vChild.Rec.OrgTotalPrice.AsFloat;
  886. fMis := fMis + vChild.Rec.MisTotalPrice.AsFloat;
  887. fOth := fOth + vChild.Rec.OthTotalPrice.AsFloat;
  888. end;
  889. ANode.Rec.OrgTotalPrice.AsFloat := TotalPriceRoundTo(fOrg);
  890. ANode.Rec.MisTotalPrice.AsFloat := TotalPriceRoundTo(fMis);
  891. ANode.Rec.OthTotalPrice.AsFloat := TotalPriceRoundTo(fOth);
  892. ANode.Rec.TotalPrice.AsFloat := TotalPriceRoundTo(fOrg + fMis + fOth);
  893. CalculateDesignPrice(ANode);
  894. end;
  895. procedure TBillsCompileData.Calculate(ABillsID: Integer);
  896. procedure UpdateParent(ANode: TBillsIDTreeNode; ADifferOrg, ADifferMis, ADifferOth: Double);
  897. begin
  898. if not Assigned(ANode) then Exit;
  899. with ANode.Rec do
  900. begin
  901. OrgTotalPrice.AsFloat := TotalPriceRoundTo(OrgTotalPrice.AsFloat + ADifferOrg);
  902. MisTotalPrice.AsFloat := TotalPriceRoundTo(MisTotalPrice.AsFloat + ADifferMis);
  903. OthTotalPrice.AsFloat := TotalPriceRoundTo(OthTotalPrice.AsFloat + ADifferOth);
  904. TotalPrice.AsFloat := TotalPriceRoundTo(
  905. TotalPrice.AsFloat + ADifferOrg + ADifferMis + ADifferOth);
  906. if DgnQuantity1.AsFloat <> 0 then
  907. DgnPrice.AsFloat := PriceRoundTo(TotalPrice.AsFloat/DgnQuantity1.AsFloat);
  908. end;
  909. UpdateParent(TBillsIDTreeNode(ANode.Parent), ADifferOrg, ADifferMis, ADifferOth);
  910. end;
  911. var
  912. vNode: TBillsIDTreeNode;
  913. iChild: Integer;
  914. fOrg, fMis, fOth: Double;
  915. begin
  916. vNode := TBillsIDTreeNode(BillsCompileTree.FindNode(ABillsID));
  917. if not Assigned(vNode) then Exit;
  918. fOrg := vNode.Rec.OrgTotalPrice.AsFloat;
  919. fMis := vNode.Rec.MisTotalPrice.AsFloat;
  920. fOth := vNode.Rec.OthTotalPrice.AsFloat;
  921. CalculateBills(vNode);
  922. fOrg := vNode.Rec.OrgTotalPrice.AsFloat - fOrg;
  923. fMis := vNode.Rec.MisTotalPrice.AsFloat - fMis;
  924. fOth := vNode.Rec.OthTotalPrice.AsFloat - fOth;
  925. UpdateParent(TBillsIDTreeNode(vNode.Parent), fOrg, fMis, fOth);
  926. end;
  927. procedure TBillsCompileData.CalculateDesignPrice(ANode: TBillsIDTreeNode);
  928. begin
  929. if ANode.Rec.DgnQuantity1.AsFloat <> 0 then
  930. ANode.Rec.DgnPrice.AsFloat := PriceRoundTo(
  931. ANode.Rec.TotalPrice.AsFloat/ANode.Rec.DgnQuantity1.AsFloat)
  932. else
  933. ANode.Rec.DgnPrice.Clear;
  934. end;
  935. procedure TBillsCompileData.ExpandPegXmjNode;
  936. function HasPegChild(ANode: TBillsIDTreeNode): Boolean;
  937. var
  938. NextNode: TBillsIDTreeNode;
  939. begin
  940. Result := False;
  941. NextNode := TBillsIDTreeNode(ANode.NextNode);
  942. while ((NextNode.MajorIndex - ANode.MajorIndex) <= ANode.PosterityCount) do
  943. begin
  944. if CheckPeg(NextNode.Rec.Name.AsString) then
  945. begin
  946. Result := True;
  947. Break;
  948. end;
  949. NextNode := TBillsIDTreeNode(NextNode.NextNode);
  950. end;
  951. end;
  952. function HasGclChild(ANode: TBillsIDTreeNode): Boolean;
  953. var
  954. vChild: TBillsIDTreeNode;
  955. begin
  956. Result := True;
  957. vChild := TBillsIDTreeNode(ANode.FirstChild);
  958. while Assigned(vChild) and not Result do
  959. begin
  960. if vChild.Rec.B_Code.AsString <> '' then
  961. Result := False;
  962. vChild := TBillsIDTreeNode(vChild.NextSibling);
  963. end;
  964. end;
  965. var
  966. iIndex: Integer;
  967. vNode: TBillsIDTreeNode;
  968. begin
  969. for iIndex := 0 to BillsCompileTree.Count - 1 do
  970. begin
  971. vNode := TBillsIDTreeNode(BillsCompileTree.Items[iIndex]);
  972. if vNode.HasChildren then
  973. vNode.Expanded := HasPegChild(vNode) or not HasGclChild(vNode);
  974. end;
  975. end;
  976. end.