BillsCompileDm.pas 34 KB

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